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 :

classer des clés en fonction de leur valeurs communes


Sujet :

Python

  1. #1
    Candidat au Club
    Homme Profil pro
    graphiste
    Inscrit en
    Février 2017
    Messages
    3
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 58
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : graphiste

    Informations forums :
    Inscription : Février 2017
    Messages : 3
    Points : 3
    Points
    3
    Par défaut classer des clés en fonction de leur valeurs communes
    - j'ai un dictionnaire: d= {'A': [tg, 17], 'B': [59, 60], 'C': [60, 61], 'D': [57, tt], 'E': [61, tg], 'F': [tt, 59]}
    - chaque clé a deux valeurs
    - on retrouve chacune des valeurs dans un autre item, sauf deux.
    - j'ai cherché une solution qui me permettrait de récupérer, classer les valeurs dans une liste en fonction de l'autre valeur à laquelle elle est associée.
    le résultat devrait être celui-là. [17,tg,61,60,59,tt,57]
    Nom : sbs.png
Affichages : 160
Taille : 67,0 Ko


    j'espere que quelqu'un aura la solution.

  2. #2
    Expert éminent Avatar de BufferBob
    Profil pro
    responsable R&D vidage de truites
    Inscrit en
    Novembre 2010
    Messages
    3 035
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : responsable R&D vidage de truites

    Informations forums :
    Inscription : Novembre 2010
    Messages : 3 035
    Points : 8 400
    Points
    8 400
    Par défaut
    salut,

    une solution au pied levé (py 3.8) :
    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
    d = {'A': ['tg', 17], 'B': [59, 60], 'C': [60, 61], 'D': [57, 'tt'], 'E': [61, 'tg'], 'F': ['tt', 59]}
     
    # on construit un dico inverse qui renvoit la liste
    # des couples de valeurs [v1, v2] pour chaque valeur v{1,2}
    # {  17: [['tg', 17]],
    #    57: [[57, 'tt']],
    #    'tg': [['tg', 17], [61, 'tg']],
    #    60: [[59, 60], [60, 61]], ... }
    dico = dict()
    for i in d.values():
        for j in i:
            dico[j] = dico.get(j, []) + [i]
     
    # on récupère un des bouts de la liste, c'est facile il n'a qu'une seule occurrence
    m = min(l := [j for i in d.values() for j in i], key=l.count) # py 3.8
     
    z = [m]
    v1, v2 = dico[m][0]
    v = v1 if v2 == m else v2 # on récupère l'autre valeur du couple
    z.append(v)
     
    while len(dico[v]) > 1: # tant qu'on est pas sur l'autre bout de la chaine
        v1, v2 = [i for i in dico[v] if m not in i][0]
        m = v
        v = v1 if v2 == m else v2
        z.append(v)
     
    print(z)
    et le résultat :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    [17, 'tg', 61, 60, 59, 'tt', 57]

  3. #3
    Candidat au Club
    Homme Profil pro
    graphiste
    Inscrit en
    Février 2017
    Messages
    3
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 58
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : graphiste

    Informations forums :
    Inscription : Février 2017
    Messages : 3
    Points : 3
    Points
    3
    Par défaut
    tout d'abord! merci beaucoup. c'est exactement ce que je voulais.
    j'ai juste un souci, je ne peux utiliser que la version 2.7 de python.
    donc pour la variable m. j'ai écrit ça:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    m = min(Counter([(i[0]) for i in d.values()]+ [(i[1]) for i in d.values()]))
    c'est très grossier, et ça ne fonctionne pas dans toutes les consoles python.
    y aurait-il un moyen d'avoir la première occurrence, sans Counter et sous 2.7 ?
    si j'abuse de votre temps, je comprendrais. en tout cas merci beaucoup

  4. #4
    Expert éminent Avatar de BufferBob
    Profil pro
    responsable R&D vidage de truites
    Inscrit en
    Novembre 2010
    Messages
    3 035
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : responsable R&D vidage de truites

    Informations forums :
    Inscription : Novembre 2010
    Messages : 3 035
    Points : 8 400
    Points
    8 400
    Par défaut
    Citation Envoyé par uncharming Voir le message
    y aurait-il un moyen d'avoir la premiere occurrence, sans Counter et sous 2.7 ?
    yep :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    # m = min(l := [j for i in d.values() for j in i], key=l.count)
    l = [j for i in d.values() for j in i]
    m = min(l, key=l.count)
    ou avec Counter() :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    l = Counter([j for i in d.values() for j in i])
    m = min(l, key=l.get)
    Citation Envoyé par uncharming Voir le message
    si j'abuse de votre temps, je comprendrais
    de mon temps non, de la politique du moindre effort certainement

  5. #5
    Candidat au Club
    Homme Profil pro
    graphiste
    Inscrit en
    Février 2017
    Messages
    3
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 58
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : graphiste

    Informations forums :
    Inscription : Février 2017
    Messages : 3
    Points : 3
    Points
    3
    Par défaut
    merci beaucoup. merci pour le temps investi. cette solution est nickel.

  6. #6
    Expert éminent
    Avatar de Pyramidev
    Homme Profil pro
    Développeur
    Inscrit en
    Avril 2016
    Messages
    1 469
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Développeur

    Informations forums :
    Inscription : Avril 2016
    Messages : 1 469
    Points : 6 102
    Points
    6 102
    Par défaut
    Bonjour,

    C'est dommage de devoir utiliser Python 2. Cette version de Python est obsolète.

    À part ça, dans l'apprentissage, au début, on est content d'avoir un code qui marche. Mais, petit à petit, il faut s'entraîner à faire un code soigné.

    Voici un code plus soigné, en Python 3 :
    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
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
     
    import doctest
    import sys
    import unittest
     
     
    def check_if_graph_is_line_and_get_consecutive_nodes(graph):
        """
        >>> graph = {'edge12': ['node1', 'node2'], 'edge23': ['node2', 'node3']}
        >>> check_if_graph_is_line_and_get_consecutive_nodes(graph)
        ['node1', 'node2', 'node3']
        >>> graph = {'edge12': ['node1', 'node2'], 'edge34': ['node3', 'node4']}
        >>> check_if_graph_is_line_and_get_consecutive_nodes(graph)
        Traceback (most recent call last):
            ...
        ValueError: The graph is not a line.
        """
        # Example: graph = {'edge12': ['node1', 'node2'], 'edge23': ['node2', 'node3']}
        _check_the_graph_format(graph)
        dict_node_edges = _build_dict_node_edges(graph)
        # Example: dict_node_edges == {
        #     'node1': ['edge12'],
        #     'node2': ['edge12', 'edge23'],
        #     'node3': ['edge23']
        # }
        dict_edge_count_node = _build_dict_edge_count_node(dict_node_edges)
        # Example: dict_edge_count_node == {1: ['node1', 'node3'], 2: ['node2']}
        _check_if_the_graph_is_a_line(dict_edge_count_node)
        result = _build_line(graph, dict_node_edges, dict_edge_count_node)
        # Example: result == ['node1', 'node2', 'node3']
        return result
     
     
    def _check_the_graph_format(graph):
        """
        >>> graph = {'edge12': ['node1', 'node2'], 'edge23': ['node2', 'node3']}
        >>> _check_the_graph_format(graph)
        """
        assert isinstance(graph, dict)
        assert graph
        for edge, nodes in graph.items():
            assert isinstance(edge, str)
            assert isinstance(nodes, list)
            assert len(nodes) == 2
            node1, node2 = nodes
            assert isinstance(node1, (int, str))
            assert isinstance(node2, (int, str))
            assert node1 != node2
     
     
    def _build_dict_node_edges(graph):
        """
        >>> graph = {'edge12': ['node1', 'node2'], 'edge23': ['node2', 'node3']}
        >>> _build_dict_node_edges(graph) == {
        ...     'node1': ['edge12'],
        ...     'node2': ['edge12', 'edge23'],
        ...     'node3': ['edge23'],
        ... }
        True
        """
        dict_node_edges = dict()
        for edge, nodes in graph.items():
            for node in nodes:
                dict_node_edges.setdefault(node, []).append(edge)
        return dict_node_edges
     
     
    def _build_dict_edge_count_node(dict_node_edges):
        """
        >>> dict_node_edges = {
        ...     'node1': ['edge12'],
        ...     'node2': ['edge12', 'edge23'],
        ...     'node3': ['edge23'],
        ... }
        >>> _build_dict_edge_count_node(dict_node_edges)
        {1: ['node1', 'node3'], 2: ['node2']}
        """
        dict_edge_count_node = dict()
        for node, edges in dict_node_edges.items():
            dict_edge_count_node.setdefault(len(edges), []).append(node)
        return dict_edge_count_node
     
     
    def _check_if_the_graph_is_a_line(dict_edge_count_node):
        """
        >>> dict_edge_count_node = {1: ['node1', 'node3'], 2: ['node2']}
        >>> _check_if_the_graph_is_a_line(dict_edge_count_node)
        """
        # Check if 2 nodes have 1 edge and all the other nodes have 2 edges.
        if len(dict_edge_count_node.get(1, [])) != 2 or set(dict_edge_count_node) - {1, 2} != set():
            raise ValueError("The graph is not a line.")
     
     
    def _build_line(graph, dict_node_edges, dict_edge_count_node):
        """
        >>> graph = {'edge12': ['node1', 'node2'], 'edge23': ['node2', 'node3']}
        >>> dict_node_edges = {
        ...     'node1': ['edge12'],
        ...     'node2': ['edge12', 'edge23'],
        ...     'node3': ['edge23'],
        ... }
        >>> dict_edge_count_node = {1: ['node1', 'node3'], 2: ['node2']}
        >>> _build_line(graph, dict_node_edges, dict_edge_count_node)
        ['node1', 'node2', 'node3']
        """
        current_node = dict_edge_count_node[1][0]
        current_edge = dict_node_edges[current_node][0]
        result = [current_node]
        while True:
            node1, node2 = graph[current_edge]
            next_node = node1 if node1 != current_node else node2
            result.append(next_node)
            next_node_edges = dict_node_edges[next_node]
            if len(next_node_edges) == 1:
                break  # end of the line
            edge1, edge2 = next_node_edges
            next_edge = edge1 if edge1 != current_edge else edge2
            current_node = next_node
            current_edge = next_edge
        return result
     
     
    class Test(unittest.TestCase):
        def test_good_line(self):
            graph = {
                'A': ['tg', 17],
                'B': [59, 60],
                'C': [60, 61],
                'D': [57, 'tt'],
                'E': [61, 'tg'],
                'F': ['tt', 59],
            }
            nodes = check_if_graph_is_line_and_get_consecutive_nodes(graph)
            self.assertEqual(nodes, [17, 'tg', 61, 60, 59, 'tt', 57])
     
        def test_one_edge(self):
            graph = {'edge12': [1, 2]}
            nodes = check_if_graph_is_line_and_get_consecutive_nodes(graph)
            self.assertEqual(nodes, [1, 2])
     
        def test_disconnected_graph(self):
            graph = {
                'edge12': [1, 2],
                'edge23': [2, 3],
                'edge45': [4, 5],
                'edge56': [5, 6],
            }
            with self.assertRaises(ValueError):
                check_if_graph_is_line_and_get_consecutive_nodes(graph)
     
        def test_node_with_3_edges(self):
            graph = {
                'edge12': [1, 2],
                'edge13': [1, 3],
                'edge14': [1, 4],
            }
            with self.assertRaises(ValueError):
                check_if_graph_is_line_and_get_consecutive_nodes(graph)
     
     
    if __name__ == "__main__":
        failure_count, _ = doctest.testmod()
        if failure_count != 0:
            sys.exit(1)
        unittest.main()
    Remarques :
    • Il ne faut pas oublier la gestion d'erreurs. Si l'entrée du programme n'a pas le format attendu, alors le code doit signaler une erreur. Sinon, en cas d'entrée au mauvais format, le code se comporte un peu n'importe comment et il est difficile de comprendre ce qu'il se passe.
    • Les codes dans les docstrings sont exécutés par doctest.testmod() : si on introduit une erreur dans un code d'une docstring, alors le programme retourne un message d'erreur. Pour plus de détails, voir la documentation du module doctest.
    • Dans la classe Test, les fonctions avec un nom qui commence par test sont vérifiées par unittest.main(). Pour plus de détails, voir la documentation du module unittest.
    • En temps normal, j'aurais fait du typage statique vérifié par mypy et, à la place de manipuler directement des int et des str, j'aurais créé des classes Node et Edge. Mais, uncharming, comme je ne sais pas où tu en es dans l'apprentissage de Python, j'ai évité d'introduire trop de concepts dans mon code.
    • Un découpage de fonction en sous-fonctions peut faciliter la compréhension de l'algorithme.
    • Les tests automatisés permettent de détecter facilement les erreurs quand on modifie le code. Certains tests unitaires servent aussi de documentation pour laquelle on a la garantie qu'elle est à jour (notamment les doctests).
    • Il faut soigner les noms des variables. Même s'il y a des cas où des noms de variables d'une seule lettre sont justifiés, en général, il faut choisir des noms de variables significatifs.


    EDIT 22h06 : petite amélioration du code.
    EDIT 22h15 : ajout d'une remarque sur la gestion d'erreurs.
    EDIT 22h21 : correction d'une erreur de nommage dans un test unitaire.
    EDIT 22h31 : correction du code : ajout de l'appel à sys.exit(1) si les doctests échouent.
    EDIT 22h49 : correction d'une remarque sur les doctests.
    EDIT 23h51 : correction du code : accepter un graphe n'ayant que deux nœuds.
    EDIT 23h56 : amélioration du code : ajout d'un contrôle : graphe non vide.

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. [XL-2010] Modifier la position des rectangles en fonction de leur valeur
    Par vbaétude dans le forum Macros et VBA Excel
    Réponses: 3
    Dernier message: 14/06/2019, 06h33
  2. [AC-2013] Cacher des champs dans un état en fonction de leurs valeurs
    Par Defaultuser01 dans le forum Access
    Réponses: 1
    Dernier message: 01/05/2014, 03h59
  3. Fusion de cellules en fonction de leur valeur
    Par Eusebe dans le forum BIRT
    Réponses: 9
    Dernier message: 29/04/2010, 17h56
  4. Afficher des résultats en fonction d'une valeur de liste
    Par subnox dans le forum VBA Access
    Réponses: 13
    Dernier message: 14/08/2007, 11h54
  5. Récuperer des fichiers en fonction de leur ancienneté
    Par julien000 dans le forum Langage
    Réponses: 3
    Dernier message: 24/07/2006, 17h09

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