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. #1
    Futur Membre du Club
    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
    Points : 8
    Points
    8
    Par défaut Update de dictionnaire sans écrasement des valeurs de même clef ?
    Bonjour,

    Je rencontre un problème assez embêtant depuis quelques jours :

    J'ai deux dictionnaires sur lesquels j'aimerais effectuer des mises à jour périodiques de valeurs pour des clefs identiques l 'un par rapport l'autre.

    Exemple : si j'ai un dico1 = {'haha' : {'hihi' : 'hoho'}} et un dico2 = {'haha' : {'huhu' : 'hehe'}}, j'aimerai pouvoir réaliser une "update" qui permettrait d'avoir un dico1 updaté à : dico1 = {'haha' : {{'hihi' : 'hoho'}, {'huhu' : 'hehe'}}}

    Le problème de la fonction update est qu'elle écrase systématiquement la valeur pour une même clef, alors que je voudrais au contraire que les deux valeurs s'imbriquent.

    Pour l'instant j'essaie de me débrouiller avec des boucles mais bon.

    Quelqu'un connaitrait-il une bonne méthode/bibliothèque qui permet de faire ça plus simplement ? Merci par avance.

  2. #2
    Membre éprouvé
    Homme Profil pro
    Inscrit en
    Décembre 2007
    Messages
    758
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : France

    Informations professionnelles :
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Décembre 2007
    Messages : 758
    Points : 970
    Points
    970
    Par défaut
    bonjour,

    c'est le bon moment pour sous-classer la méthode update des dictionnaires afin de pouvoir faire ce que tu veux
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    class MonDict(dic):
        def __init__(self,*args,**kwargs):
            dict.__init__(self,*args,**kwargs)
        def update(self,other):
            for key,item in other.iteritems():
                if key in self:
                    dict.update(self[key],item)
    c'est très certainement incomplet, mais c'est pour donner l'idée.

  3. #3
    Membre éclairé
    Avatar de airod
    Homme Profil pro
    Gérant Associé, DMP Santé et Directeur technique
    Inscrit en
    Août 2004
    Messages
    767
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Gérant Associé, DMP Santé et Directeur technique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Août 2004
    Messages : 767
    Points : 891
    Points
    891
    Par défaut
    utiliser des dico comme valeur alors qu'un tuple suffirait!
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
     
    a={'a':[('b','c'),('d','e')]}
     
    b={'a':[('f','g')],'x':[('u','v')]}
     
    for k in a:
        item=b.setdefault(k,[])
        a[k]=a[k]+item
        b.pop(k)
     
    a.update(b)
    print a
    je ferais un truc de ce type.... maintenant si ta structure doit impérativement etre une imbrication de dico, dans des liste, alors il faut adapter.

  4. #4
    Expert éminent sénior
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 287
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Manche (Basse Normandie)

    Informations professionnelles :
    Activité : Architecte technique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2008
    Messages : 21 287
    Points : 36 776
    Points
    36 776
    Par défaut
    Salut,

    Précisez le sens que vous donnez à "s'imbrique"!
    Le problème de la fonction update est qu'elle écrase systématiquement la valeur pour une même clef, alors que je voudrais au contraire que les deux valeurs s'imbriquent.
    Sur le fond, n'oubliez pas que la "valeur" associée à la clé d'un dictionnaire peut être une référence vers un type 'complexe'.
    Un tuple vous a déjà été suggéré!

    Mais pensez aussi un autre dictionnaire, un objet, n'importe quoi...

    Enfin pas n'importe quoi, juste "Type 'Complexe'"
    Complexe dit que ce n'est pas un int, mais sa structure est suffisamment régulière pour être rangée dans une hiérarchie finie d'objets composés d'objets ou de types simples
    En conception, "composite est son nom --- une arborescence de répertoires ca le fait aussi...

    Plus compliqué que complexe sont les structures qui n'ont pas suffisamment de régularité pour être racontées, ce qui n'est pas si grave tant qu'on se réduit à transférer une représentation d'état sérialisée - i.e<; une chaine de caractères.

    Ma réflexion essaie juste de faire des liens entre votre question (*): comment faire qu'un dictionnaire soit plus qu'un machin plat où le type des attributs sont des valeurs monovaluées et atomiques?

    - W
    (*) Je sais que ce n'est pas ce que vous avez dit
    Mais n'est ce pas la question que vous avez posé (à l'insu de votre plein grè)??? Non! je ne développerais pas car, çà aboutit inexorablement dans des questions de transformations de schéma de "représentations", qui nous amène à une discussion sur le rôle de la monnaie... Le forum Python n'est pas fait pour çà!!!
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

  5. #5
    Futur Membre du Club
    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
    Points : 8
    Points
    8
    Par défaut
    lol wiztricks, mes dictionnaires sont précisément ceux-là aux "valeurs plus compliquées que les structures 'complexes' " dont tu parles, en fait ce sont des dizaines de dictionnaires imbriqués les uns dans les autres, ce qui offre justement aucune régularité (en fait c'est totalement chaotique) et rend leur parcours très difficile.

    Merci pour vos réponses, je vais sans doute suivre le conseil de kango et recréer ma propre méthode update.

  6. #6
    Membre expérimenté
    Homme Profil pro
    Inscrit en
    Mars 2007
    Messages
    941
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations forums :
    Inscription : Mars 2007
    Messages : 941
    Points : 1 384
    Points
    1 384
    Par défaut
    Cela va dépendre de la sémantique associée, mais le parcours de dictionnaires imbriqués n'est pas particulièrement complexe avec une fonction récursive, sur ce modèle:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    def parcours(d):
        for k, v in d.items();
            if isinstance(v, dict):
                r = parcours(v)
                # traitement r
            else:
                # traitement v et/ou k
        # return qqch

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

    Informations forums :
    Inscription : Mars 2010
    Messages : 53
    Points : 64
    Points
    64
    Par défaut solution en 2 lignes ?
    Grâce au type 'set', j'ai une solution toute simple :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    def update(a, b):
        for key in set(a.keys()) & set(b.keys()):# equivalent: set(a.keys()).intersection(set(b.keys()))
            a[key].extend(b[key])
    Il faut, pour que ça fonctionne, que chaque 'item' du dictionnaire soit une liste, fût-ce d'un seul élément.
    Exemple:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    c={'a':[{'b':'c'},{'d':'e'}], 'x':[{'coucou':'beu'}]}
    d={'a':[{'f':'g'}],'x':[{'u':'v'}]}
    print 'avant:', c
    update(c,d)
    print 'apres:', c
     
    # resultat:
    avant: {'a': [{'b': 'c'}, {'d': 'e'}], 'x': [{'coucou': 'beu'}]}
    apres: {'a': [{'b': 'c'}, {'d': 'e'}, {'f': 'g'}], 'x': [{'coucou': 'beu'}, {'u': 'v'}]}

  8. #8
    Expert éminent
    Avatar de tyrtamos
    Homme Profil pro
    Retraité
    Inscrit en
    Décembre 2007
    Messages
    4 462
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Var (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Décembre 2007
    Messages : 4 462
    Points : 9 249
    Points
    9 249
    Billets dans le blog
    6
    Par défaut
    Bonjour,

    Avant d'essayer d'y répondre, j'aimerais une clarification de la question, et surtout du but à atteindre.

    En effet, ça, ça marche:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    dico1 = {'haha' : {'hihi' : 'hoho'}}
     
    print dico1['haha']
    {'hihi': 'hoho'}
     
    print dico1['haha']['hihi']
    'hoho'
    Mais ça, ça ne marche pas:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    dico1 = {'haha' : {{'hihi' : 'hoho'}, {'huhu' : 'hehe'}}}
     
    SyntaxError: invalid syntax
    Le but est-il de placer les sous-dicos dans un tuple comme suit?

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    dico1 = {'haha' : ({'hihi' : 'hoho'}, {'huhu' : 'hehe'})}
     
    print dico1['haha']
    ({'hihi': 'hoho'}, {'huhu': 'hehe'})
     
    print dico1['haha'][1]['huhu']
    'hehe'
    ???

    Tyrtamos
    Un expert est une personne qui a fait toutes les erreurs qui peuvent être faites, dans un domaine étroit... (Niels Bohr)
    Mes recettes python: http://www.jpvweb.com

  9. #9
    Expert éminent sénior
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 287
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Manche (Basse Normandie)

    Informations professionnelles :
    Activité : Architecte technique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2008
    Messages : 21 287
    Points : 36 776
    Points
    36 776
    Par défaut
    salut,
    J'ai du boulot en ce moment et je ne peux pas trop gratter sur cette question intéressante, mais:
    Citation Envoyé par miawaw Voir le message
    Il faut, pour que ça fonctionne, que chaque 'item' du dictionnaire soit une liste, fût-ce d'un seul élément.
    Si on veut généraliser la chose, il faut une classe X héritée d'un dict dont les valeurs sont une collection(*) de X ou un simple X.

    (*)Une liste, un uplet, un dict sont des collections, mais si on veut une structure régulière, il faut que X soit une feuille ou un dict de X.

    Dans les patrons de conception cela s'appelle un composite.

    Après on veut faire des choses tordues comme, soient:
    a = X
    b = X
    c = intersection (a, b)
    ou
    c = réunion de (a, b)

    Ce qui pose une question d'adressage et de comparaisons. X est un "arbre", on a la représentation du composite mais comment identifier un élément?
    Si c'est une hiérarchie de dict, on pense folders d'un système de fichiers et l'identité d'un élément pourrait être /a/b/c/.... ou a.b.c.

    Code Python : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    class Folder(dict):
        def __init__(self, **kwds):
            super(Folder, self).__init__(self, kwds)
            self.__dict__ = self
        def union(self, folder): pass
        def intersection (self, folder): pass
        ...

    Partons de X=Folder, c'est un composite!
    a = Folder(dict(b=Folder(), c=Folder)))
    qui permet d'avoir accès aux éléments de 'a' sous la forme
    a['b'] ou a.b
    Les feuilles de la chose sont des types autres que Folder.
    Exemple: a.b.c = 123 crée l'attribut 'c' dans le Folder 'a.b' et lui assigne l'entier 123

    Bon faut que je retourne gratter

    - W
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

  10. #10
    Futur Membre du Club
    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
    Points : 8
    Points
    8
    Par défaut Proposition de code
    Tyrtamos effectivement erreur de ma part : les valeurs seraient forcément soit des dict soit des list.

    Miawaw ta fonction ne marche qu'au premier niveau du dictionnaire mais l'idée initiale de l'utilisation des listes m'a finalement bien aidé. Dividee merci d'avoir mentionner la récursivité comme solution.

    Mon code est le suivant (l'idée est que les deux dict vont être updatés mutuellement, j'ai pas trouvé mieux pour le moment) :

    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
    def parcours(d1, d2):
    	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)
    	for (k1, v1),(k2, v2) in zip(d1.items(), d2.items()) :#on parcourt d1 et d2 en parallele
    		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)
    			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
    				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) :
    				parcours(v1, v2)			
    	return d1
     
    c={'a':{'b':{'hihi':'huhu'}}, 'x':{'coucou':'beu'}, 'y':{'coucou':'beu'}}
    d={'a':{'b':{'hihi':['haha','hyhy']}},'c':{'u':'v'}}
    par = parcours(c, d)
    print '\nOn a maintenant c update:\n\n', par
    Le résultat :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    On a maintenant c update:
     
    {'a': {'b': {'hihi': ['huhu', ['haha', 'hyhy']]}}, 'x': {'coucou': 'beu'}, 'c':
    {'u': 'v'}, 'y': {'coucou': 'beu'}}
    J'espère que j'ai pas oublié de "cas particulier" à traiter...

    Si vous avez une remarque à faire n'hésitez pas, les débutants sont toujours heureux d'apprendre :p

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

    Informations forums :
    Inscription : Mars 2010
    Messages : 53
    Points : 64
    Points
    64
    Par défaut
    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
    stop = True
    def update(a ,b):
        #     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 'normaux'.
        # 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.
        try:
            intersec = set(a.keys()) & set(b.keys())
            ##for key in set(b.keys()) - set(a.keys()):
            ##    a[key] = b[key]
            if intersec: # les dicos on des cles identiques.
                for key in intersec:
                    if update(a[key], b[key]):
                        a[key] = [a[key]]
                        a[key].extend([b[key]])
            else: # pas d'elements communs
                return stop
        except: # il a au moins un element qui n'est pas un dictionnaire:
            return stop
    C'est donc une fonction recursive, et tout à l'air de bien fonctionner. Par contre les elements de d qui ne sont pas dans c ne sont pas ajoutés à c. Si on veut qu'ils se rajoutent à c, il suffit d'enlever les lignes precedees des double #. (deux lignes en tout)
    Test de la 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
    c={'a':{'b':{'hihi':'huhu'}}, 'x':{'coucou':'beu'}, 'y':{'coucou':'beu'}}
    d={'a':{'b':{'hihi':['haha','hyhy']}},'c':{'u':'v'}}
    print c
    print d
    print "-" * 80
    update(c,d)
    print c
     
    ## affichage dans la console :
    {'a': {'b': {'hihi': 'huhu'}}, 'x': {'coucou': 'beu'}, 'y': {'coucou': 'beu'}}
    {'a': {'b': {'hihi': ['haha', 'hyhy']}}, 'c': {'u': 'v'}}
    --------------------------------------------------------------------------------
    {'a': {'b': {'hihi': ['huhu', ['haha', 'hyhy']]}}, 'x': {'coucou': 'beu'}, 'y': {'coucou': 'beu'}}
     
    ## en supprimant les ##, on aurait:
    {'a': {'b': {'hihi': ['huhu', ['haha', 'hyhy']]}}, 'x': {'coucou': 'beu'}, 'c': {'u': 'v'}, 'y': {'coucou': 'beu'}}

    J'ai modifié un peu la fonction en
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    def update(a ,b, ajout=False):
    pour avoir le choix. Version finale, sans commentaires:
    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
    stop = True
    def update(a ,b, ajout=False):
        try:
            if ajout:
                for k in set(b.keys()) - set(a.keys()):
                    a[k] = b[k]
            intersec = set(a.keys()) & set(b.keys())
            if intersec:
                for key in intersec:
                    if update(a[key], b[key], ajout):
                        a[key] = [a[key]]
                        a[key].extend([b[key]])
            else:
                return stop
        except:
            return stop

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

    Informations forums :
    Inscription : Mars 2010
    Messages : 53
    Points : 64
    Points
    64
    Par défaut
    uhm que se passe-t-il si on ecrit
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    update(a,b)
    update(a,b)
    le dico a ne devrait pas être modifié lors du deuxieme appel, il faudrait, dans ma fonction, modifier la clause "except" en y faisant des tests du genre "if not b in a : a .append(b) # si a une liste" (un truc du genre).

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

    Informations forums :
    Inscription : Mars 2010
    Messages : 53
    Points : 64
    Points
    64
    Par défaut
    Attention, j'ai dit
    Citation Envoyé par miawaw Voir le message
    Version finale, sans commentaires:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    ...
            if ajout:
                for k in set(b.keys()) - set(a.keys()):
                    a[k] = b[k]
            intersec = set(a.keys()) & set(b.keys())
    mais il faut bien sur definir 'intersec' avant de faire la boucle. Le bon ordre est:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    intersec = set(a.keys()) & set(b.keys())
    if ajout:
        for k in set(b.keys()) - set(a.keys()):
            a[k] = b[k]

  14. #14
    Membre extrêmement actif
    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
    Points : 1 658
    Points
    1 658
    Par défaut
    1)

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
            else :# on parcourt le reste de l'arborescence.
                if isinstance(v1, dict) & isinstance(v2, dict) :
                    parcours(v1, v2)
    Ce else: signifie que v1 is v2 est True, c’est à dire que v1 et v2 sont deux références du même objet.

    [ Dès lors, il est inutile de tester isinstance(v1, dict) & isinstance(v2, dict) : tester isinstance(v1, dict) suffit. Mais ce n’est pas l’essentiel. ]

    Quand v1 is v2 est True et qu’ils sont tous deux des dictionnaires, ils repartent dans parcours(v1,v2).

    Étant identiques, les deux boucles for key in d2.keys() : et for key in d1.keys() : ne vont pas modifier d1 et d2 , c'est a dire v1 et v2.

    Étant identiques encore, chaque couple (k1, v1),(k2, v2) délivré par la boucle for (k1, v1),(k2, v2) in zip(d1.items(), d2.items()) : va être tel que (k1, v1) et (k2, v2) seront identiques, càd k1==k2 True et v1==v2 True. Donc v1 is not v2 va être False et le programme va aller dans la section

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
            else :# on parcourt le reste de l'arborescence.
                if isinstance(v1, dict) & isinstance(v2, dict) :
                    parcours(v1, v2)
    • Là, si v1 et v2 ne sont pas des dictionnaires..... il ne va rien se passer du tout: la récursivité seraallée jusqu’au bout d’une branche de traitement et elle va remonter d’un cran.
    • Et si v1 et v2 sont encore des dictionnaires, ils vont repartir dans un traitement parcours(v1,v2) , mais, étant identiques, le processus va nécessairement arriver de la même façon au bout de la récursivité (une fois ou plusieurs fois) mais de toute façon avec ce même résultat: il ne se passe rien.



    Conclusion cette section commandée par le else: est superflue.
    J’ai testé en l’éliminant, je n’ai pas connstaté de problème.





    2)

    L’algorithme est défectueux pour la raison suivante:

    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
    print '\n\n=========================================================================='
    A = {'atrae':'MOREd','hihi':['haha','hyhy'],'wert':'wert_d','4f5g':'4f5g_d'}
    B = {'hihi':['haha','hyhy'],'wert':'wert_d','atrae':'MOREd','4f5g':'4f5g_d'}
     
    print "expression definissant le dictionnaire A :\n"\
          +"A = {'atrae':'MOREd','hihi':['haha','hyhy'],'wert':'wert_d','4f5g':'4f5g_d'}"
    print 'dictionnaire A :\n   ',A
    print "\nexpression definissant le dictionnaire B :\n"\
          +"B = {'hihi':['haha','hyhy'],'wert':'wert_d','atrae':'MOREd','4f5g':'4f5g_d'}"
    print 'dictionnaire B :\n   ', B
     
    print '\nA==B  est ',A==B
    print 'A.items()==B.items()  est ',A.items()==B.items()
    print 'type(A.items()) =',type(A.items()),'    type(B.items()) =',type(B.items())
    print 'A is B  est ',A is B
     
     
    print '\niteration dans A.items() ='
    for yui in A.items():
        print yui
     
    print '\niteration dans B.items() ='
    B = {'hihi':['haha','hyhy'],'wert':'wert_d','atrae':'MOREd','4f5g':'4f5g_d'}
    for yui in B.items():
        print yui

    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
    expression definissant le dictionnaire A :
    A = {'atrae':'MOREd','hihi':['haha','hyhy'],'wert':'wert_d','4f5g':'4f5g_d'}
    dictionnaire A :
        {'hihi': ['haha', 'hyhy'], '4f5g': '4f5g_d', 'atrae': 'MOREd', 'wert': 'wert_d'}
    
    expression definissant le dictionnaire B :
    B = {'hihi':['haha','hyhy'],'wert':'wert_d','atrae':'MOREd','4f5g':'4f5g_d'}
    dictionnaire B :
        {'atrae': 'MOREd', '4f5g': '4f5g_d', 'hihi': ['haha', 'hyhy'], 'wert': 'wert_d'}
    
    A==B  est  True
    A.items()==B.items()  est  False
    type(A.items()) = <type 'list'>     type(B.items()) = <type 'list'>
    A is B  est  False
    
    iteration dans A.items() =
    ('hihi', ['haha', 'hyhy'])
    ('4f5g', '4f5g_d')
    ('atrae', 'MOREd')
    ('wert', 'wert_d')
    
    iteration dans B.items() =
    ('atrae', 'MOREd')
    ('4f5g', '4f5g_d')
    ('hihi', ['haha', 'hyhy'])
    ('wert', 'wert_d')

    Le fait que A is B et A.items()==B.items() soient tous deux False alors que du point de vue logiqueA==B est True donne lieu à des incidents de traitement menant à des résultats faux dans certains cas. Tous les cas similaires ne donnent pas des résultats faux, cela dépend des clés et des valeurs, mais il suffit de cas non conformes pour rendre l’algorithme incorrect.



    Pour suivre le déroulement, j’ai ajouté des instructions dans le code.
    Il faut mettre aff=1 dans la liste de paramètres pour obtenir l’affichage des infos à certaines étapes.

    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
    def parcours(d1, d2, aff = 0):
        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)
        if aff:
            print '-------- entree dans parcours de d1 et d2 --------------------------'
            print 'd1 =\n',d1
            print 'd2 =\n',d2
        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)
                    if aff:
                        print '\nOn repart sur parcours(v1, v2) avec v1 is not v2'
                    parcours(v1, v2)
                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)
        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 = "CAS 1 On est parti de:\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 ecr
    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 = "CAS 2 On est parti de:\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 ecr
    print "par['a']['b'] ="
    for xpar in par['a']['b'].items():  print xpar
    print




    En lançant le programme une fois sur les dictionnaires suivants (remarquer que c[’a’][’b’] et d[’a’][’b’] ont les mêmes clés et que les items y sont écrits dans les expressions respectives dans un ordre des clés identique pour les deux)

    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'} }

    et une autre fois sur les dictionnaires suivants ( les mêmes clés sont encore dans c[’a’][’b’] et d[’a’][’b’] mais les items sont en ordre différent dans d[’a’][’b’] ):

    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 obtient donc ces résultats:

    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
    CAS 1 On est parti de:
    c['a']['b'] =
    ('hihi', 'huhu')
    ('4f5g', '45_c')
    ('atrae', 'MOREc')
    ('wert', 'wert_c')
     
    d['a']['b'] =
    ('hihi', ['haha', 'hyhy'])
    ('4f5g', '4f5g_d')
    ('atrae', 'MOREd')
    ('wert', 'wert_d')
     
    par['a']['b'] =
    ('hihi', ['huhu', ['haha', 'hyhy']])
    ('4f5g', ['45_c', '4f5g_d'])
    ('atrae', ['MOREc', 'MOREd'])
    ('wert', ['wert_c', 'wert_d'])
    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
    CAS 2 On est parti de:
    c['a']['b'] =
    ('hihi', 'huhu')
    ('4f5g', '45_c')
    ('atrae', 'MOREc')
    ('wert', 'wert_c')
     
    d['a']['b'] =
    ('atrae', 'MOREd')
    ('4f5g', '4f5g_d')
    ('hihi', ['haha', 'hyhy'])
    ('wert', 'wert_d')
     
    par['a']['b'] =
    ('hihi', ['huhu', 'MOREd'])
    ('4f5g', ['45_c', '4f5g_d'])
    ('atrae', ['MOREc', ['haha', 'hyhy']])
    ('wert', ['wert_c', 'wert_d'])


    Dans le CAS 2 , le problème est que c[’a’][’b’].items() et d[’a’][’b’].items() ne sont pas identiques et que l’itération for (k1, v1),(k2, v2) in zip(d1.items(), d2.items()) : délivre des couples (k1, v1),(k2, v2) dans lesquels k1 et k2 ne sont pas égaux, comme on peut le vérifier en faisant toutner le code ci-dessous avec aff==1:


    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
    -------- entree dans parcours de d1 et d2 --------------------------
    d1 =
    {'b': {'hihi': 'huhu', '4f5g': '45_c', 'atrae': 'MOREc', 'wert': 'wert_c'}}
    d2 =
    {'b': {'atrae': 'MOREd', '4f5g': '4f5g_d', 'hihi': ['haha', 'hyhy'], 'wert': 'wert_d'}}
     
    k1 : v1  =  b : {'hihi': 'huhu', '4f5g': '45_c', 'atrae': 'MOREc', 'wert': 'wert_c'}
    k2 : v2  =  b : {'atrae': 'MOREd', '4f5g': '4f5g_d', 'hihi': ['haha', 'hyhy'], 'wert': 'wert_d'}
     
    On repart sur parcours(v1, v2) avec v1 is not v2
    -------- entree dans parcours de d1 et d2 --------------------------
    d1 =
    {'hihi': 'huhu', '4f5g': '45_c', 'atrae': 'MOREc', 'wert': 'wert_c'}
    d2 =
    {'atrae': 'MOREd', '4f5g': '4f5g_d', 'hihi': ['haha', 'hyhy'], 'wert': 'wert_d'}
     
    k1 : v1  =  hihi : huhu
    k2 : v2  =  atrae : MOREd
    zip(d1.items(), d2.items()) =
    [(('hihi', 'huhu'), ('atrae', 'MOREd')), (('4f5g', '45_c'), ('4f5g', '4f5g_d')), (('atrae', 'MOREc'), ('hihi', ['haha', 'hyhy'])), (('wert', 'wert_c'), ('wert', 'wert_d'))]
     
    k1 : v1  =  4f5g : 45_c
    k2 : v2  =  4f5g : 4f5g_d
    zip(d1.items(), d2.items()) =
    [(('hihi', ['huhu', 'MOREd']), ('atrae', 'MOREd')), (('4f5g', '45_c'), ('4f5g', '4f5g_d')), (('atrae', 'MOREc'), ('hihi', ['haha', 'hyhy'])), (('wert', 'wert_c'), ('wert', 'wert_d'))]
     
    k1 : v1  =  atrae : MOREc
    k2 : v2  =  hihi : ['haha', 'hyhy']
    zip(d1.items(), d2.items()) =
    [(('hihi', ['huhu', 'MOREd']), ('atrae', 'MOREd')), (('4f5g', ['45_c', '4f5g_d']), ('4f5g', '4f5g_d')), (('atrae', 'MOREc'), ('hihi', ['haha', 'hyhy'])), (('wert', 'wert_c'), ('wert', 'wert_d'))]
     
    k1 : v1  =  wert : wert_c
    k2 : v2  =  wert : wert_d
    zip(d1.items(), d2.items()) =
    [(('hihi', ['huhu', 'MOREd']), ('atrae', 'MOREd')), (('4f5g', ['45_c', '4f5g_d']), ('4f5g', '4f5g_d')), (('atrae', ['MOREc', ['haha', 'hyhy']]), ('hihi', ['haha', 'hyhy'])), (('wert', 'wert_c'), ('wert', 'wert_d'))]





    3)

    Il y a un autre problème, cette fois quand les clés de c[’a’][’b’] et celles de d[’a’][’b’] ne sont pas les mêmes.

    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
     
    -------------- Fin de l'updating -------------------------
     
    On est parti de:
     
    c['a']['b'] =
    ('hihi', 'huhu')
    ('bb', 'bb_c')
     
    d['a']['b'] =
    ('hihi', ['haha', 'hyhy'])
    ('wert', 'wert_d')
     
    On obtient c apres updating:
     
    par['a']['b'] =
    ('hihi', ['huhu', ['haha', 'hyhy']])
    ('wert', ['wert_d', 'bb_c'])
    ('bb', ['bb_c', 'wert_d'])

    Ce qui se passe est que les deux premières itérations à l’entrée dans parcours() modifient les deux arguments entrés d’une manière telle que les clés ne sont pas dans le même ordre dans les deux arguments dictionnaires modifiés.
    Et on se retrouve dans le même cas qu’en 2).

    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
     
    -------- entree dans parcours de d1 et d2 --------------------------
    d1 =
    {'b': {'hihi': 'huhu', 'bb': 'bb_c'}}
    d2 =
    {'b': {'hihi': ['haha', 'hyhy'], 'wert': 'wert_d'}}
     
    k1 : v1  =  b : {'hihi': 'huhu', 'bb': 'bb_c'}
    k2 : v2  =  b : {'hihi': ['haha', 'hyhy'], 'wert': 'wert_d'}
     
    On repart sur parcours(v1, v2) avec v1 is not v2
    -------- entree dans parcours de d1 et d2 --------------------------
    d1 =
    {'hihi': 'huhu', 'wert': 'wert_d', 'bb': 'bb_c'}
    d2 =
    {'hihi': ['haha', 'hyhy'], 'bb': 'bb_c', 'wert': 'wert_d'}
     
    k1 : v1  =  hihi : huhu
    k2 : v2  =  hihi : ['haha', 'hyhy']
    zip(d1.items(), d2.items()) =
    [(('hihi', 'huhu'), ('hihi', ['haha', 'hyhy'])), (('wert', 'wert_d'), ('bb', 'bb_c')), (('bb', 'bb_c'), ('wert', 'wert_d'))]
     
    k1 : v1  =  wert : wert_d
    k2 : v2  =  bb : bb_c
    zip(d1.items(), d2.items()) =
    [(('hihi', ['huhu', ['haha', 'hyhy']]), ('hihi', ['haha', 'hyhy'])), (('wert', 'wert_d'), ('bb', 'bb_c')), (('bb', 'bb_c'), ('wert', 'wert_d'))]
     
    k1 : v1  =  bb : bb_c
    k2 : v2  =  wert : wert_d
    zip(d1.items(), d2.items()) =
    [(('hihi', ['huhu', ['haha', 'hyhy']]), ('hihi', ['haha', 'hyhy'])), (('wert', ['wert_d', 'bb_c']), ('bb', 'bb_c')), (('bb', 'bb_c'), ('wert', 'wert_d'))]

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


    Il va falloir affiner ce code. Ou prendre celui de miawaw s’il tient la route. J’ai l’impression que pour des dictionnaires plus touffus, le code de miawaw risque de produire des choses inattendues aussi. Je vais regarder ça.

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

    Informations forums :
    Inscription : Mars 2010
    Messages : 53
    Points : 64
    Points
    64
    Par défaut
    waou, quelle réponse.
    Je crois que ça va chauffer pour moi .
    personnellement, j'ai l'impression que mon code, étant simple, a moins de chance de soufrir de gros problèmes, mais je suis très intéressé par l'analyse que pourrait en faire eyquem.

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

    Informations forums :
    Inscription : Mars 2010
    Messages : 53
    Points : 64
    Points
    64
    Par défaut
    Avant de recevoir un sermon de la part de eyquem (je rigole..), j'e voulais améliorer ma fonction: pour ne pas créer des doublons bêtement, j'ai pensé à la chose suivante :
    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
     
    # ...
    if intersec: # les dicos on des cles identiques.
        for key in intersec:
            if update(a[key], b[key], ajout):
            # comment faire l'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,
            # s'il n'y est pas encore: a[k].append(b[k]) ou a[k] = b[k] + [a[k]], 
            #     en fonction de qui est la liste.
            # 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]]
    # ...
    J'ai défini la petite fonction:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    def islist(x):
        return type(x) == type([]) # c'est pas joli joli, mais j'ai pas d'autre idée
    Ca a l'air d'être assez bien:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    if __name__ == "__main__":
        A = {'atrae':'MOREd','hihi':['haha','hyhy'],'wert':'wert_d','4f5g':'4f5g_d', 'pierre':{'paul':{'paul':'jean'}}}
        B = {'hihi':['haha','hyhy'],'wert':'wert_d','atrae':'MOREd','4f5g':['4f5g_d', 'dites 33'], 'pierre':{'paul':{'paul':'jacques'}}}
        update(A,B)
        print "A updated :", A
     
    ## donne à la sortie :
    A updated : {'hihi': ['hyhy', 'haha'], '4f5g': ['4f5g_d', 'dites 33'], 'atrae': 'MOREd', 'pierre': {'paul': {'paul': ['jean', 'jacques']}}, 'wert': 'wert_d'}
    Allez, j'espère que ça tiendra.

  17. #17
    Futur Membre du Club
    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
    Points : 8
    Points
    8
    Par défaut
    Merci pour ton analyse eyquem.

    Si j'ai bien compris, le problème du code (points (2) et (3)) serait en fait simplement lié à l'ordre des clefs dans les dictionnaires, ce qui fait que le parcours (k1,v1), (k2,v2) ne tiendrait pas la route.

    J'ai donc écris quelque chose pour pallier à mon sens à ce problème :

    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
    def syncKeyDic(A, B) :
    	A1 = {}
    	B1 = {}
    	for k1 in A.keys():
    		A1[k1] = A.get(k1)
    		B1[k1] = B.get(k1)
    	syncDicList = []
    	syncDicList.append(A1)
    	syncDicList.append(B1)
     
    	return syncDicList
     
    list = syncKeyDic(A, B)
     
    A = list[0]
    B = list[1]
     
    print "expression definissant le dictionnaire A :\n"\
          +"A = {'atrae':'MOREd','hihi':['haha','hyhy'],'wert':'wert_d','4f5g':'4f5g_d'}"
    print "\nexpression definissant le dictionnaire B :\n"\
          +"B = {'hihi':['haha','hyhy'],'wert':'wert_d','atrae':'MOREd','4f5g':'4f5g_d'}"
    print '\ndictionnaire A  apres passage dans la fonction syncKeyDic():\n   ',A
    print '\ndictionnaire B  apres passage dans la fonction syncKeyDic():\n   ', B
    print '\nA==B  est ',A==B
    print 'A.items()==B.items()  est ',A.items()==B.items()
    print 'type(A.items()) =',type(A.items()),'    type(B.items()) =',type(B.items())
    print 'A is B  est ',A is B
    Ce code serait placé juste après l'ajustement des keys manquantes de part et d'autres des deux dictionnaires au début du code.

    Resultat après :

    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
    expression definissant le dictionnaire A :
    A = {'atrae':'MOREd','hihi':['haha','hyhy'],'wert':'wert_d','4f5g':'4f5g_d'}
    dictionnaire A :
        {'hihi': ['haha', 'hyhy'], '4f5g': '4f5g_d', 'atrae': 'MOREd', 'wert': 'wert
    _d'}
    
    expression definissant le dictionnaire B :
    B = {'hihi':['haha','hyhy'],'wert':'wert_d','atrae':'MOREd','4f5g':'4f5g_d'}
    dictionnaire B :
        {'atrae': 'MOREd', '4f5g': '4f5g_d', 'hihi': ['haha', 'hyhy'], 'wert': 'wert
    _d'}
    
    dictionnaire A  apres passage dans la fonction syncKeyDic():
        {'atrae': 'MOREd', '4f5g': '4f5g_d', 'hihi': ['haha', 'hyhy'], 'wert': 'wert
    _d'}
    
    dictionnaire B  apres passage dans la fonction syncKeyDic():
        {'atrae': 'MOREd', '4f5g': '4f5g_d', 'hihi': ['haha', 'hyhy'], 'wert': 'wert
    _d'}
    
    A==B  est  True
    A.items()==B.items()  est  True
    type(A.items()) = <type 'list'>     type(B.items()) = <type 'list'>
    A is B  est  False
    Je ne comprends pas pourquoi 'A is B' est toujours 'False' alors que les deux structures sont maintenant identiques en valeurs et en ordre. Ou alors j'ai pas compris la nature du comparateur 'is' et il se trouve que le problème par rapport à la fonction de départ se trouve quand même réglé malgré ça.

  18. #18
    Membre expérimenté
    Homme Profil pro
    Inscrit en
    Mars 2007
    Messages
    941
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations forums :
    Inscription : Mars 2007
    Messages : 941
    Points : 1 384
    Points
    1 384
    Par défaut
    'A is B' n'est vrai que si A et B sont deux références au même objet. Toute modification à l'objet référencé par A sera visible à travers B (si cet objet est mutable bien entendu):
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    >>> A = {}
    >>> B = A
    >>> A is B
    True
    >>> A[0]=1
    >>> B
    {0: 1}
    En C, on parlerait d'égalité de pointeurs.

    Ta fonction synckeyDic ne renverra pas deux dictionnaires aux clés identiques si certaines clés de B n'apparaissent pas dans A. Et même si les clés sont identiques, ton code dépend du fait que l'ordre de parcours des clés est déterminé par l'ordre d'insertion uniquement. Cela semble être une hypothèse raisonnable mais je ne suis pas certain que cela fasse partie de la sémantique des dictionnaires. Au minimum, je mettrais un gros commentaire pour préciser que la postcondition dépend de cette hypothèse...

  19. #19
    Membre extrêmement actif
    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
    Points : 1 658
    Points
    1 658
    Par défaut
    Ta fonction synckeyDic ne renverra pas deux dictionnaires aux clés identiques si certaines clés de B n'apparaissent pas dans A.
    La fonction syncKeyDic() est destinée à être activée sur d1,d2 après les lignes
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
        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)
    qui complètent réciproquement les dictionnaires d1 et d2 en items qui manquent à chacun à partir de la présence dans l’autre dictionnaire des items manquants.







    Et même si les clés sont identiques, ton code dépend du fait que l'ordre de parcours des clés est déterminé par l'ordre d'insertion uniquement.
    C’est ce qui semble se passer en effet: l’ordre d’itération a l’air de dépendre de l’ordre d’insertion de façon univoque.

    Je l’ai vérifié sur quelques cas mais quelques cas ne suffise pas à prouver que c’est la règle universelle.


    Pour que ce soit une règle universelle, il faut que

    - la relation entre l’ordre d’insertion et l’ordre d’itération soit constante dans le temps pour une définition de dictionnaire précise et fixée:
    pour n’importe quelle instance du type dictionnaire créée à partir d’une définition précise et fixée , et pour n’importe quel essai d’itération effectué dans cette instance, il faut que l’ordre d’itération soit constant

    - pour n'importe quel sorte de dictionnaire, qu’il ait 3 items ou 500000, et quelle que soit la complexité des clés, l’ordre d’itération doit être constamment le même aussi



    Dans le cas du problème de Buck, il y a une question supplémentaire:

    - dans la mesure où il veut itérer dans deux dictionnaires de façon concommitante en obtenant les items des 2 dictionnaires dans le même ordre des clés, ces deux dictionnaires ayant des clés identiques mais pas les mêmes valeurs pour les mêmes clés (sinon aucun intérêt), l’ordre d’itération d’un dictionnaire dépend il aussi des valeurs dans le dictionnaire, ou seulement des clès ?




    La réponse ne peut se fonder que sur la connaissance de la façon dont une itération lit un dictionnaire et de la façon dont un dictionnaire est constitué dans un certain rangement à partir d’une définition.
    Et moi je n'en sais rien.

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

    Informations forums :
    Inscription : Mars 2010
    Messages : 53
    Points : 64
    Points
    64
    Par défaut
    @eyquem: J'ai l'impression que tu as l'habitude de 'faire des tests', alors.. : quels dictionnaires devrais-je utiliser pour vérifier ma fonction (cf. post 11,12,13,16), pour voir si elle est water-proof (ou bullet-proof) ?

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