IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Python Discussion :

Update de dictionnaire sans écrasement des valeurs de même clef ?


Sujet :

Python

  1. #21
    Membre Expert
    Profil pro
    Inscrit en
    Janvier 2007
    Messages
    1 418
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2007
    Messages : 1 418
    Par défaut
    Salut miawaw,


    Je te sens plein d’enthousiasme et de délectation à utiliser Python, c’est bien.

    Tes codes m’intéressent mais je n’ai pas eu le temps de m’y plonger, d’autant plus que c’est compliqué de s’y retrouver dans deux développements sur un même sujet suivis en même temps.
    Mais je compte bien regarder un de ces 4.

    Pour ce qui est des tests, il est vrai que j’aime bien vérifier des choses qui ne sont pas suffisamment bien décrites ou même abordées dans les docs, et confirmer la validité de choix de code par des tests. Mais je ne suis pas particulièrement calé en Python, ni en tests. Et sans regarder en détail, ce n’est pas bien possible de proposer quelque chose.

    L’idée de base de ton algorithme, ne pas itérer de façon concommitante sur deux dictionnaires comme le fait Buck, me semble pas mal, j’ai l’impression que l’algo est juste , cependant en même temps il me paraït trop simple pour ne pas avoir quelque chose de reprochable, mais je ne sais pas quoi.

  2. #22
    Membre éclairé
    Profil pro
    Inscrit en
    Mars 2010
    Messages
    53
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Mars 2010
    Messages : 53
    Par défaut
    Ah, je ne voulais pas te mettre la pression.
    Je vais créer des petits exemples tordus moi-même, si je vois qqchose j'en ferai part ici.

  3. #23
    Membre Expert
    Profil pro
    Inscrit en
    Janvier 2007
    Messages
    1 418
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2007
    Messages : 1 418
    Par défaut
    le problème du code (points (2) et (3)) serait en fait simplement lié à l'ordre des clefs dans les dictionnaires

    Je dirais plutôt qu’il est dû à la différence existant entre l'ordre de création du dictionnaire (= l'ordre des items existant dans la définition qui sert à créer le dictionnaire = ce que dividee appelle l'ordre d'insertion) et l'ordre de rangement dans lequel se retrouvent des items dans la représentation interne, puisque l'ordre dans lequel est itéré un dictionnaire (et qui doit être un simple parcours du rangement des items dans la représentation interne) est différent de l'ordre de création.
    En effet, du fait de cette différence, les dictionnaires sont communément dits “non ordonnés“ et ton expression est ambigue.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    AK = ('atrae','hihi','wert','4f5g')
    AV = ('MOREd',['haha','hyhy'],'wert_d','4f5g_d')
    deek = {}
    for i in xrange(len(AK)):
        deek[AK[i]] = AV[i]
     
    print'         AK =',AK
    print '\ndeek.keys() =',deek.keys()
    print '\ndeek.items() =\n',deek.items()
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
             AK = ('atrae', 'hihi', 'wert', '4f5g')
     
    deek.keys() = ['hihi', '4f5g', 'atrae', 'wert']
     
    deek.items() =
    [('hihi', ['haha', 'hyhy']), ('4f5g', '4f5g_d'), ('atrae', 'MOREd'), ('wert', 'wert_d')]
    Cette différence est dûe, je crois, au fait que les items ne sont pas rangés sur la base des clés mais des clés hashées.
    Évidemment, dans leur représentation interne, les dictionnaires sont bien rangés selon un certain ordre, sinon il ne serait pas possible de retrouver une valeur à partir de sa clé, et c'est de cet ordre dont tu parles.



    Puisque l’ordre de rangement des items dans la représentation interne ne se manifeste et n'est constatable qu'au travers de l’ordre d’itération, il vaut mieux ne se référer qu’à l’ordre d’itération.

    En fait les problèmes rencontrés dans ton code sont plus exactement liés au fait que l’ordre d’itération d’un dictionnaire ne dépend pas de façon univoque seulement de l’ENSEMBLE des clés mais plus précisément de la LISTE des clés exprimée dans la définition du dictionnaire, puisque ce que j’appelle l’ordre de création dans cette définition est ce qui compte véritablement.

    C’est ce que montre le code suivant déjà vu sous une autre forme:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    AK = ('atrae','hihi','wert','4f5g')
    AV = ('MOREd',['haha','hyhy'],'wert_d','4f5g_d')
    BK = ('hihi', 'wert', 'atrae', '4f5g')
    BV = (['haha','hyhy'],'wert_d','MOREd','4f5g_d')
    deekA = {}
    for i in xrange(len(AK)):
        deekA[AK[i]] = AV[i]
    deekB = {}
    for i in xrange(len(BK)):
        deekB[BK[i]] = BV[i]
     
    print'AK = ',AK
    print'BK = ',BK
    print '\ndeekA.keys() =',deekA.keys()
    print 'deekB.keys() =',deekB.keys()
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    AK =  ('atrae', 'hihi', 'wert', '4f5g')
    BK =  ('hihi', 'wert', 'atrae', '4f5g')
     
    deekA.keys() = ['hihi', '4f5g', 'atrae', 'wert']
    deekB.keys() = ['atrae', '4f5g', 'hihi', 'wert']

    ---------------------------------------------------


    Quelques précisions sur syncKeyDic() avant de passer à l’algorithme global

    1) on peut écrire plus simplement
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    def syncKeyDic(A, B) :
        A1,B1 = {},{}
        for k1 in A.keys():
            A1[k1] = A[k1]
            B1[k1] = B[k1]
        return A1,B1
    2) appeler une référence list, qui est un mot réservé est une très mauvaise pratique

    3) vue la simplicité de l’algorithme de syncKeyDic(), on peut se passer de le mettre dans une fonction, ceci suffit:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    for key in d2.keys() :
        #on met a jour d1 par rapport aux keys de d2
        #pour le bon parcours en zip() plus tard
        if key not in d1.keys() :
            d1[key] = d2[key]
    for key in d1.keys() :
        #on met a jour d2 par rapport aux keys de d1
        #pour le bon parcours en zip() plus tard
        if key not in d2.keys() :
            d2[key] = d1[key]
    A,B = {},{}
    for k in d1.iterkeys():
        A[k],B[k] = d1[k],d2[k]
    d1,d2 = A,B
    Soit dit en passant, get() est inutile:
    d2.get(key) renvoie d2[key] si key est dans d2 et None si key n'y est pas.
    Mais étant dans une boucle for key in d2.keys(): on est sûr que key est dans d2.



    -------------------------------------------------


    Ta fonction syncKeyDic() est effectivement un pas vers une correction de ton code, mais il y a un hic. Deux hic en fait.


    Redéfinir d1 et d2 au sein de la fonction parcours() entraine un problème.

    Ce qui entre dans la fonction parcours() , ce sont les références d1 et d2 de deux objets que je vais appeler objet-d1 et objet-d2.
    Ce que j’appelle objet est une zone mémoire enceinte dans une délimitation.
    Et quand j’écris «références d1 et d2» , ce sont bien des références, c’est à dire des noms et non pas les objets eux mêmes, étant entendu que les arguments sont passés par appel de valeur, mais que ce sont des valeurs de références, pas les objets eux mêmes qui sont appelés: cf la citation un peu plus bas.


    Les références sont comme des étiquettes qui sont collées et décollées des objets au gré des instructions exécutées par un programme. Ces étiquettes sont strictement parlant de nature chaîne et sont enregistrées telles dans l’espace de nom ( un espace de noms étant lui même un dictionnaire qui assure le mapping entre les étiquettes et les objets en mémoire.. enfin bref...)
    Mais ce dont il s’agit en l’occurence, c’est d’un espace de nom LOCAL, c’est à dire celui d’une fonction parcours() dans lequel sont introduites deux références d1 et d2.

    The local namespace for a function is created when the function is called, and deleted when the function returns or raises an exception that is not handled within the function.
    http://docs.python.org/tutorial/clas...and-namespaces

    The actual parameters (arguments) to a function call are introduced in the local symbol table of the called function when it is called; thus, arguments are passed using call by value (where the value is always an object reference, not the value of the object).
    http://docs.python.org/tutorial/cont...ning-functions


    Or la fonction parcours() est une fonction récursive.
    Un espace de nom local de cette fonction est donc celui d’un niveau récursif donné, auquel se trouve le programme au moment où il fait les manipulations: car un nouvel espace de noms est créé à chaque appel de la fonction à un niveau récursif supplémentaire:
    The local namespace for a function is created when the function is called, and deleted when the function returns or raises an exception that is not handled within the function. (Actually, forgetting would be a better way to describe what actually happens.) Of course, recursive invocations each have their own local namespace.
    http://docs.python.org/tutorial/clas...and-namespaces


    Plaçons nous dans une fonction parcours() d’un niveau de récursion que nous appellerons NR.

    Je disais que ce qui entre dans la fonction parcours() , ce sont deux références d1 et d2 de deux objets appelés objet-d1 et objet-d2.
    Ceci signifie que objet-d1 et objet-d2 existaient avant l’appel de la fonction parcours() au niveau récursif NR, c’est à dire qu’ils sont des zones mémoire référencées dans l’espace de noms de la fonction parcours() appelée en niveau NR-1.
    Cependant, dire que les références d1 et d2 entrent dans la fonction n’est pas correct. En réalité il faut comprendre que les références d1 et d2 qui existent dans l’espace de noms de niveau NR-1 sont RECOPIÉES dans un espace de noms de niveau NR créé par l’appel à la fonction récursive de niveau NR. C’est en tous cas ce que je comprends dans ceci:
    The actual parameters (arguments) to a function call are introduced in the local symbol table of the called function when it is called; thus, arguments are passed using call by value (where the value is always an object reference, not the value of the object). When a function calls another function, a new local symbol table is created for that call.


    Donc je pars de cette idée, que je traduis en disant que :
    dans l’espace de noms de niveau récursif NR-1 il y a deux références d1[NR-1] et d2[NR-1]
    dans l’espace de noms de niveau récursif NR il y a deux références d1[NR] et d2[NR]
    qui désignent des objets identiques:
    d1[NR-1] et d1[NR] référencent le même objet-d1
    d2[NR-1] et d2[NR] référencent le même objet-d2

    Quand on fait A,B = {},{} , on crée deux nouveaux objets en mémoire, objet-A et objet-B, sur lesquels on colle les étiquettes A et B.

    Puis quand on fait d1,d2 = A,B (c’est à dire d1=A et d2=B , pour qu’il n’y ait pas d’ambigüité) dans la fonction parcours() de niveau récursif NR, on déplace l’étiquette d1[NR] de objet-d1 sur objet-A et l’étiquette d2[NR] de objet-d2 sur objet-B.
    Après ce transfert, objet-A a deux étiquettes d1[NR] et A ,
    et objet-B a deux étiquettes B et d2[NR]

    En d’autres circonstances, objet-d1 et objet-d2 n’auraient plus d’étiquette et disparaitraient donc, c’est à dire qu’ils ne pourraient plus être atteints car plus aucune référence ne les tiendraient au registre de l’espace de noms.

    Cependant, ici, objet-d1 et objet-d2 continuent d’être référencés par d1[NR-1] et d2[NR-1] dans le niveau récursif NR-1.
    Et il se trouve que c’est eux que l’on aimerait voir modifiés par l’action de la fonction parcours() de niveau NR.
    C’était le cas avant l’introduction de la fonction syncKeyDic() .
    Mais ce n’est plus le cas avec la fonction syncKeyDic() car on modifie en réalité les objet-A et objet-B dans parcours() de niveau NR, sans que cette fonction renvoie le résultat de ces modifications au niveau supérieur NR-1.




    Le code suivant permet de vérifier que les objets référencés par v1,v2 qui entrent dans un niveau de récursion NR de la fonction récursive se retrouvent bien à l’entrée de ce niveau avec les mêmes adresses sous les noms d1,d2
    et qu’après synchronisation des clés, les noms d1,d2 repèrent des objets différents, dont les modifications ne peuvent pas se répercuter au niveau NR-1 comme précédemment.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    def parcours(d1, d2, NR = 0, aff = 0):
        print '\n--- Niveau recursif : ',NR,' -------------------'
        print 'id(d1) =',id(d1)
        print 'id(d2) =',id(d2),'\n'
     
        for key in d2.keys() :#on met a jour d1 par rapport aux keys de d2
            #pour le bon parcours en zip() plus tard
            if key not in d1.keys() :
                d1[key] = d2.get(key)
        for key in d1.keys() :#on met a jour d2 par rapport aux keys de d1
            #pour le bon parcours en zip() plus tard
            if key not in d2.keys() :
                d2[key] = d1.get(key)
     
        A,B = {},{}
        for k in d1.iterkeys():
            A[k],B[k] = d1[k],d2[k]
        print 'id(A) =',id(A)
        print 'id(B) =',id(B)
        d1,d2 = A,B
        print 'id(d1) =',id(d1),'   apres synchronisation des cles'
        print 'id(d2) =',id(d2),'   apres synchronisation des cles'
     
        if aff:
            print '-------- entree dans parcours de d1 et d2 --------------------------'
            print 'd1 =\n',d1
            print 'd2 =\n',d2
            print '\nd1.items() =\n',d1.items()
            print '\nd2.items() =\n',d2.items()
     
        for (k1, v1),(k2, v2) in zip(d1.items(), d2.items()) :
            #on parcourt d1 et d2 en parallele
            if aff:
                print
                print 'k1 : v1  = ',k1,":",v1
                print 'k2 : v2  = ',k2,":",v2
            if v1 is not v2 :
                if isinstance(v1, dict) & isinstance(v2, dict) :
                    # si v1 et v2 sont differents en tant que dict,
                    # une recursivite modifiera ces valeurs en tant que clef
                    # (2eme ligne du code)
                    print '\nOn repart sur parcours(v1, v2) avec v1 is not v2'
                    print 'id(v1) =',id(v1)
                    print 'id(v2) =',id(v2)
                    d1[k1] = parcours(v1, v2, NR+1)
                else :
                    # on a affaire a au moins une valeur de type different que dict
                    # (on ira pas plus loin du coup) :
                    # une liste va imbriquer les deux valeurs
                    if aff:
                        print 'zip(d1.items(), d2.items()) =\n',zip(d1.items(), d2.items())
                    listDic = []
                    listDic.append(v1)
                    listDic.append(v2)
                    d1[k1] = listDic
            else :# on parcourt le reste de l'arborescence.
                if isinstance(v1, dict) & isinstance(v2, dict) :
                    if aff:
                        print '\nOn repart sur parcours(v1, v2) cette fois avec v1 is v2'
                    parcours(v1, v2)
        if aff:
            print '\nd1 de sortie =\n',d1
        return d1
     
     
    ###########################################################################
    c={ 'a':{'b':{'atrae':'MOREc','hihi':'huhu','wert':'wert_c','4f5g':'45_c'}}, 'x':{'coucou':'beu'}, 'y':{'coucou':'beu'} }
    d={ 'a':{'b':{'atrae':'MOREd','hihi':['haha','hyhy'],'wert':'wert_d','4f5g':'4f5g_d'}}, 'c':{'u':'v'} }
    # On enregistre les valeurs de c['a']['b'] et d['a']['b'] dans une chaine
    ecr = "On est parti de:\n\nc['a']['b'] =\n"
    for xc in c['a']['b'].items():  ecr += repr(xc)+'\n'
    ecr += "\nd['a']['b'] =\n"
    for xd in d['a']['b'].items():  ecr += repr(xd)+'\n'
     
    par = parcours(c, d)
    print "\nCAS 1 -------------- Fin de l'updating -------------------------\n"
     
    print ecr
    print "On obtient c apres updating:\n"
    print "par['a']['b'] ="
    for xpar in par['a']['b'].items():  print xpar
    print
     
    ###########################################################################
    c={ 'a':{'b':{'atrae':'MOREc','hihi':'huhu','wert':'wert_c','4f5g':'45_c'}}, 'x':{'coucou':'beu'}, 'y':{'coucou':'beu'} }
    d={ 'a':{'b':{'hihi':['haha','hyhy'],'wert':'wert_d','atrae':'MOREd','4f5g':'4f5g_d'}}, 'c':{'u':'v'} }
    # On enregistre les valeurs de c['a']['b'] et d['a']['b'] dans une chaine
    ecr = "On est parti de:\n\nc['a']['b'] =\n"
    for xc in c['a']['b'].items():  ecr += repr(xc)+'\n'
    ecr += "\nd['a']['b'] =\n"
    for xd in d['a']['b'].items():  ecr += repr(xd)+'\n'
     
    par = parcours(c, d)
    print "\nCAS 2 -------------- Fin de l'updating -------------------------\n"
     
    print ecr
    print "On obtient c apres updating:\n"
    print "par['a']['b'] ="
    for xpar in par['a']['b'].items():  print xpar
    print


    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    --- Niveau recursif :  0  -------------------
    id(d1) = 17485376
    id(d2) = 17502832 
     
    id(A) = 17503120
    id(B) = 17503264
    id(d1) = 17503120    apres synchronisation des cles
    id(d2) = 17503264    apres synchronisation des cles
     
    On repart sur parcours(v1, v2) avec v1 is not v2
    id(v1) = 17485520
    id(v2) = 17485232
     
    --- Niveau recursif :  1  -------------------
    id(d1) = 17485520
    id(d2) = 17485232 
     
    id(A) = 17504128
    id(B) = 17503552
    id(d1) = 17504128    apres synchronisation des cles
    id(d2) = 17503552    apres synchronisation des cles
     
    On repart sur parcours(v1, v2) avec v1 is not v2
    id(v1) = 17484944
    id(v2) = 17502976
     
    --- Niveau recursif :  2  -------------------
    id(d1) = 17484944
    id(d2) = 17502976 
     
    etc




    ---------------------------------------------------------


    La solution est de produire ce renvoi par une petit modification du code:
    remplacer
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    if v1 is not v2 :#difference de value : traitement
        if isinstance(v1, dict) & isinstance(v2, dict) :
            #si v1 et v2 sont differents en tant que dict,
            #une recursivite modifiera ces valeurs
            #en tant que clef (2eme ligne du code)
            parcours(v1, v2)
    par
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    if v1 is not v2 :#difference de value : traitement
        if isinstance(v1, dict) & isinstance(v2, dict) :
            #si v1 et v2 sont differents en tant que dict,
            #une recursivite modifiera ces valeurs
            #en tant que clef (2eme ligne du code)
            d1[k1] = parcours(v1, v2)





    ---------------------------------------------------

    Le second hic est que la réponse à la question suivante n’est pas connue:

    la dépendance dans laquelle se trouve l’ordre d’itération par rapport à l’ordre de création est-elle bien univoque, constante et universelle sur tous les dictionnaires ?

    Si ce n’était pas le cas, il y aurait le risque de rencontrer des cas particuliers où les clés de deux dictionnaires, même après synchronisation de leurs itérations, ne seraient pas parcourues de façon concommitante exacte, en clair ça foirerait.

    Comme le dit dividee:
    Au minimum, je mettrais un gros commentaire pour préciser que la postcondition dépend de cette hypothèse...
    Et le mieux serait de chercher un algorithme qui élimine complétement ce risque.

  4. #24
    Membre éclairé
    Profil pro
    Inscrit en
    Mars 2010
    Messages
    53
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Mars 2010
    Messages : 53
    Par défaut
    @Buck92:
    Pourrais-je avoir un exemple de deux dictionnaires A et B où la fonction de mise à jour ne fonctionne pas.
    Tu dis quel résultat tu veux obtenir.
    Je vais essayer chez moi, ce problème m'intéresse toujours

  5. #25
    Membre averti
    Profil pro
    Inscrit en
    Mars 2010
    Messages
    12
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Mars 2010
    Messages : 12
    Par défaut
    Resalut,

    Désolé pour le temps de latence, weekend prolongé oblige.

    J'ai lu pour le moment en diagonale le post de eyquem. Vite fait et sans avoir la certitude du problème soulevé dans ce dernier, je crois l'avoir réglé (si c'est bien celui auquel je pense) par la création d'une fonction en extra en dehors de la fonction principale.

    Miawaw tu me demandes un exemple de deux dictionnaires où ça marche pas, le truc c'est qu'en ce qui me concerne les choses (ou la chance ?) font que la fonction marche jusque à présent de façon tout à fait satisfaisante (je mettrai ma 'version' du code plus tard, mais il ne diffère pas beaucoup des posts plus hauts).

    Je dois dire aussi que j'ai fait en sorte que mes deux dictionnaires ne se construisent pas d'une façon tout à fait différente, ça limite sans doute les problèmes.

  6. #26
    Membre éclairé
    Profil pro
    Inscrit en
    Mars 2010
    Messages
    53
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Mars 2010
    Messages : 53
    Par défaut
    Question :

    Prenons des dictionnaires:

    c = {"cle1": [1, 2], "cle2": ["hihi","hoho"]}
    d = {"cle1": [3, 4], "cle3": ["Lille", "Brest"]}

    Préfères-tu que le le resultat de la mise à jour de c par d soit :
    ( la difference se fait au niveau de "cle1")

    c = {"cle1": [1, 2, 3, 4],"cle2": ["hihi", "hoho"], "cle3": ["Lille", "Brest"]}

    ou

    c = {"cle1": [[1, 2], [3, 4]],"cle2": ["hihi", "hoho"], "cle3": ["Lille", "Brest"]} ?


    @eyquem: tu affiche souvent des matrices, ou autres tableaux, je me demandais si tu connaissais la fonction pprint du module pprint.
    Elle affiche les tableaux, listes, dicos de jolie manière toute seule.

  7. #27
    Membre averti
    Profil pro
    Inscrit en
    Mars 2010
    Messages
    12
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Mars 2010
    Messages : 12
    Par défaut
    Celle-là : c = {"cle1": [1, 2, 3, 4],"cle2": ["hihi", "hoho"], "cle3": ["Lille", "Brest"]}

  8. #28
    Membre éclairé
    Profil pro
    Inscrit en
    Mars 2010
    Messages
    53
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Mars 2010
    Messages : 53
    Par défaut
    La methode parcours(), sur les dictionnaires
    c={ 'a':{'b':{'atrae':'MOREc','hihi':'huhu','wert':'wert_c','4f5g':'45_c'}}, 'x':{'coucou':'beu'}, 'y':{'coucou':'beu'} }
    et
    d={ 'a':{'b':{'atrae':'MOREd','hihi':['haha','hyhy'],'wert':'wert_d','4f5g':'4f5g_d'}}, 'c':{'u':'v'} }

    donne
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    {'a': {'b': {'4f5g': ['45_c', '4f5g_d'],
                 'atrae': ['MOREc', 'MOREd'],
                 'hihi': ['huhu', ['haha', 'hyhy']],       <--
                 'wert': ['wert_c', 'wert_d']}},
     'c': ['remi', {'u': 'v'}],
     'x': {'coucou': 'beu'},
     'xxxxxx': 'yyyyyyyy',
     'y': {'coucou': 'beu'}}
    Je n'ai pas encore regardé en profondeur cette methode. Je vais regarder un peu.


    Ma fonction n'a pas ce probleme. de plus, update(c,d) suivi de update(c,d) ne modifie qu'une seule fois c (et ne modifie jamais d) .
    Remarque: si c ne doit pas etre modifie, facile: on crée une copie et le tour est joué.
    Bon, je mets le code de ma fonction comme "source d'inspiration". Etant donné la structure de ma methode, c'était facile d'effectuer les changements pour obtenir le resultat voulu ([1,2,3,4] et non [[1,2],[3,4]]). Je sais pas si ce sera facile pour ta fonction.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    stop = True
    def islist(x):
        return type(x) == type([])
     
    #     Au premier appel de la fonction, les deux elements sont
    # des dictionnaires.
    # Si les dictionnaires n'ont plus de clés communes, ce sont des elements 
    # 'disjoints' des deux dicos parents. Il faut ajouter le dico b  
    # au dico parent du dico a.
    #     Aux appels suivants, on peut ne pas avoir deux dictionnaires. 
    # Soit un dic. avec un element normal, soit deux elements.
    # Dans ce cas on entre dans la partie 'except' à cause de l'exception
    # generee par l'instruction "set(a.keys()) & set(b.keys())" parce que
    # 'keys()' ne sera pas possible pour l'un des deux elements.
     
    def update(a ,b, ajout=True):
        try:
            intersec = set(a.keys()) & set(b.keys())
     
            if ajout:
                for k in set(b.keys()) - set(a.keys()):
                    a[k] = b[k]
     
            if intersec: # les dicos on des cles identiques.
                for key in intersec:
                    if update(a[key], b[key], ajout):
                        # ajout:
                        # si les deux sont des listes, ont doit agrandir la liste: a[k] = list(set(a[k])|set(b[k]))
                        # s'il y a un element et une liste, on ajoute l'element à la liste: 
                        #     a[k].append(b[k]) ou a[k] = b[k] + [a[k]]
                        # s'il y a deux elements, on cree une liste: a[k] = [a[k], b[k]]
                        if islist(a[key]) and islist(b[key]):
                            a[key] = list(set(a[key]+b[key]))
                        elif islist(a[key]):
                            a[key] = list(set(a[key]+[b[key]]))
                        elif islist(b[key]):
                            a[key] = list(set([a[key]]+b[key]))
                        else:
                            if a[key] != b[key]:
                                a[key] = [a[key], b[key]]
            else: # pas d'elements communs
                return stop
        except: # il a au moins un element qui n'est pas un dictionnaire:
            return stop
    En gros l'idée c'est qu'on descend le plus loin possible dans "l'arborescence" commune des deux dictionnaires et lorsqu'on on au bout, on met les elements disponibles dans les deux dictionnaires dans une seule liste dns le dictionnaire c.
    EXEMPLE:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    arborescene de c:
    c --b - [1,2,3]
      \   \ 'huhu' 
       \'c' -{'u', 'v'}
     
    arborescence de d:
     
    d -- b - [2,4,5]
      \   \- 'hoho'
       \ 'c'- 'x'
     
    Les dictionnaires present sont en fait: c={b:[[1,2,3], 'huhu'], 'c':{'u','v'}}
    et d= {b:[[2,4,5], 'hoho'], 'c':'x'}.
     
    après update, c devient: {b: [[1,2,3], [2,4,5], 'huhu', 'hoho'], 'c':[{'u','v'}, 'x']}
     
    On voit que, tristement, [1,2,3] et [2,4,5] n'ont pas fusionné mais ça c'est parce que les elements pointés par b dans les deux dictionnaires sont des liste qui contiennent ces listes. (hum)
    Pour m'expliquer, je montre ce qui fonctionne:
     
    c --b - [1,2,3]
      \  
       \'c'- {'u', 'v'}
     
    d -- b - [2,4,5]
      \  
       \ 'c'- 'x' 
     
    A nouveau les listes pointées par b fusionnent, mais ici ça donne [1,2,3,4,5].

Discussions similaires

  1. Réponses: 2
    Dernier message: 13/12/2007, 15h02
  2. Récupération des valeurs select multiple sans sélection
    Par akara dans le forum Général JavaScript
    Réponses: 22
    Dernier message: 17/07/2007, 19h10
  3. Réponses: 4
    Dernier message: 06/03/2007, 13h35
  4. Passer des valeurs dans mon actionform sans les afficher
    Par tonito53 dans le forum Struts 1
    Réponses: 6
    Dernier message: 04/01/2007, 11h36
  5. Réponses: 18
    Dernier message: 03/03/2006, 18h19

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo