web-dev-qa-db-fra.com

Quel est le moyen le plus rapide d’ajouter des données à une liste sans duplication en python (2.5)

Il y a environ un demi-million d'éléments qui doivent être placés dans une liste, je ne peux pas avoir de doublons, et si un article est déjà là, je dois obtenir son index. Jusqu'ici j'ai

if Item in List:
    ItemNumber=List.index(Item)
else:
    List.append(Item)
    ItemNumber=List.index(Item)

Le problème est que, au fur et à mesure que la liste s'allonge, elle ralentit progressivement jusqu'à ce que cela ne vaille plus la peine. Je suis limité à Python 2.5 car c'est un système embarqué. 

20
Dennis

Vous pouvez utiliser un set (sous CPython depuis la version 2.4) pour rechercher efficacement des valeurs en double. Si vous avez également réellement besoin d'un système indexé, vous pouvez utiliser à la fois un ensemble et une liste.

Faire vos recherches en utilisant un ensemble enlèvera la surcharge de if Item in List, mais pas celle de List.index(Item)

Veuillez noter que ItemNumber=List.index(Item) sera très inefficace à faire après List.append(Item). Vous connaissez la longueur de la liste, votre index peut donc être récupéré avec ItemNumber = len(List)-1.

Pour supprimer complètement la surcharge de List.index (car cette méthode effectuera une recherche dans la liste - ce qui est très inefficace pour les ensembles plus volumineux), vous pouvez utiliser un mappage dict des éléments en retour à leur index.

Je pourrais le réécrire comme suit:

# earlier in the program, NOT inside the loop
Dup = {}

# inside your loop to add items:
if Item in Dup:
    ItemNumber = Dup[Item]
else:
    List.append(Item)
    Dup[Item] = ItemNumber = len(List)-1
16
lunixbochs

Si vous avez vraiment besoin de conserver les données dans un tableau, j'utiliserais un dictionnaire séparé pour garder une trace des doublons. Cela nécessite deux fois plus de mémoire, mais ne ralentira pas de manière significative.

existing = dict()
if Item in existing:
    ItemNumber = existing[Item]
else:
    ItemNumber = existing[Item] = len(List)
    List.append(Item)

Toutefois, si vous n'avez pas besoin de sauvegarder l'ordre des éléments, vous devez simplement utiliser une variable set. Cela prendra presque aussi peu de place qu'une liste, mais sera aussi rapide qu'un dictionnaire.

Items = set()
# ...
Items.add(Item) # will do nothing if Item is already added

Les deux requièrent que votre objet soit hashable . En Python, la plupart des types sont hashable sauf s'il s'agit d'un conteneur dont le contenu peut être modifié. Par exemple: lists ne sont pas obligatoire car vous pouvez modifier leur contenu, mais Tuples est obligatoire parce que vous ne pouvez pas.

Si vous essayez de stocker des valeurs qui ne peuvent pas être écrites, il n'y a pas de solution générale rapide.

9
Jeremy Banks

Vous pouvez améliorer le contrôle beaucoup:

check = set(List)

for Item in NewList:
    if Item in check: ItemNumber = List.index(Item)
    else:
        ItemNumber = len(List)
        List.append(Item)

Ou encore mieux, si l'ordre n'est pas important, vous pouvez le faire:

oldlist = set(List)
addlist = set(AddList)
newlist = list(oldlist | addlist)

Et si vous devez passer en revue les éléments dupliqués:

for item in (oldlist & addlist):
    pass # do stuff
5
orlp

Quelle est la gamme de votre demi-million d'articles? Vous pourrez peut-être utiliser la mémoire de manière très inefficace si vous pouvez faire quelques déclarations sur la plage de ces éléments. Je crois qu'une approche dans ce sens serait la plus rapide possible, mais pourrait ne pas être pratique pour une application embarquée à moins que vous ne puissiez faire des garanties très strictes.

Cette réponse aide-t-elle à vous orienter vers le compromis temps/mémoire auquel je fais allusion? Je peux aider à clarifier davantage si vous le souhaitez.

0
Brian Stinar