4 votes

Supprimer les éléments des dicts de la liste si la valeur de la clé du dict est dans l'autre liste

J'ai un code comme le suivant :

dicts = [
        {'one': 'hello',
         'two': 'world',
         'three': ['a', 'b', 'c', 'd'],
         'four': 'foo'
        },
        {'one': 'pizza',
         'two': 'cake',
         'three': ['f', 'g', 'h', 'e'],
         'four': 'bar'
        }
       ]

letters = ['q', 'w', 'e', 'r','t','y']

dedup_rows = [row for row in dicts if row['three'][3] not in letters]

L'objectif est que dedup_rows doit contenir les éléments de dicts dans laquelle le quatrième élément de la liste stockée dans three n'est pas contenu dans la liste letters . Pour l'essentiel, delete row from dicts if row['three'][3] in letters . La sortie du code ci-dessus serait :

dedup_rows: [
             {'one': 'hello',
              'two': 'world',
              'three': ['a', 'b', 'c', 'd'],
              'four': 'foo'
             }
            ]

Le code que j'ai fonctionne, mais en pratique, les deux dicts y letters contiennent des centaines de milliers d'éléments chacun et l'exécution est donc lente car chaque itération sur les dicts nécessite également une itération complète sur letters .

Existe-t-il une manière plus optimale de procéder en Python ?

4voto

Ashish Points 1019

Votre code dedup_rows = [row for row in dicts if row['three'][3] not in letters] est d'une complexité carrée, puisqu'il s'agit d'une itération sur dicts et sur letters pour chaque élément de dicts .
Si vos deux listes contiennent un grand nombre d'éléments. Vous devriez envisager une structure de données dont la complexité du temps de consultation est de l'ordre de un. Dans votre cas Jeux de Python sont parfaits. Vous pouvez en savoir plus à ce sujet.
Il suffit de convertir letters = ['q', 'w', 'e', 'r','t','y'] à un ensemble dont la syntaxe est set(letters) et trouver avec la syntaxe x in letters_set .

dicts = [
    {'one': 'hello',
     'two': 'world',
     'three': ['a', 'b', 'c', 'd'],
     'four': 'foo'
    },
    {'one': 'pizza',
     'two': 'cake',
     'three': ['f', 'g', 'h', 'e'],
     'four': 'bar'
    }
   ]

letters = ['q', 'w', 'e', 'r','t','y']
letters_set = set(letters)

dedup_rows = [row for row in dicts if row['three'][3] not in letters_set]

De cette façon, vous pouvez changer l'algorithme de l'ordre de n carré à l'ordre de n.

1voto

Jon Betts Points 256

Si vous avez réellement affaire à des centaines de milliers d'enregistrements avec des lignes contenant des centaines de milliers de valeurs chacune, alors peut-être qu'une approche purement python en mémoire n'est pas la meilleure solution.

Il y a plusieurs choses que vous pouvez faire pour améliorer les performances :

  • Introduire en continu des enregistrements à partir de votre source (fichier ? base de données ?) au lieu de les charger en une seule fois.
  • Utilisez un générateur qui lit les enregistrements un par un et les cède s'ils correspondent ou non (ne les conservez jamais dans une liste).
  • Utiliser des ensembles pour les comparaisons d'ensembles, ce qui sera beaucoup plus rapide pour de nombreuses valeurs

D'une manière générale, la question se pose de savoir d'où vous tirez ces informations.

S'ils sont stockés dans une base de données quelconque, il est préférable d'effectuer une requête à la source qui exclut les lignes que vous ne voulez pas et fournit un curseur pour parcourir les lignes que vous voulez de manière efficace sur le plan de la mémoire.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X