2013-02-27 15 views
28

Wenn ich eine Python-Liste habe, die viele Duplikate enthält, und ich möchte durch jedes Element, aber nicht durch die Duplikate iterieren, ist es am besten, eine Menge zu verwenden (wie in set(mylist), oder finde eine andere Möglichkeit, eine Liste ohne zu erstellen Duplikate? ich dachte nur durch die Liste Looping und Überprüfung auf Duplikate aber ich dachte, das ist, was set() tut, wenn es initialisiert wird.Besser/schneller zu Loop-Set oder Liste?

Also, wenn mylist = [3,1,5,2,4,4,1,4,2,5,1,3] und ich möchte wirklich nur eine Schleife durch [1,2,3,4,5] (Reihenfolge spielt keine Rolle), sollte ich set(mylist) oder etwas anderes verwenden?

Eine Alternative ist im letzten Beispiel möglich, da die Liste jede ganze Zahl zwischen ihrem min und m enthält ax Wert, ich könnte durch range(min(mylist),max(mylist)) oder set(mylist) durchlaufen. Sollte ich generell versuchen, in diesem Fall die Verwendung von Set zu vermeiden? Würden Sie die min und max langsamer finden, als nur die set zu erstellen?


In dem Fall, in dem letzten Beispiel ist die set schneller:

from numpy.random import random_integers 
ids = random_integers(1e3,size=1e6) 

def set_loop(mylist): 
    idlist = [] 
    for id in set(mylist): 
     idlist.append(id) 
    return idlist 

def list_loop(mylist): 
    idlist = [] 
    for id in range(min(mylist),max(mylist)): 
     idlist.append(id) 
    return idlist 

%timeit set_loop(ids) 
#1 loops, best of 3: 232 ms per loop 

%timeit list_loop(ids) 
#1 loops, best of 3: 408 ms per loop 
+0

Warum es nicht testen? –

+2

@JoelCornett fertig :) – askewchan

+0

Erwarten Sie, dass dieser Geschwindigkeitsunterschied tatsächlich in jedem Programm eine Rolle spielt, das Sie jemals schreiben? Halten Sie die Dinge in "numpy", mit einem Genxp anstatt eine Millionen-Element 'liste' zu ​​erstellen, nur um zu iterieren (und' xrange' anstelle von 'range' zu ​​verwenden, wenn dies Py2 ist), stattdessen versuchen, enge Schleifen in C zu machen von Python (z. B. "idlist = range (...)" anstelle einer "for" -Schleife, die das Gleiche tut), etc. werden alle Größenordnungen mehr Differenz machen. – abarnert

Antwort

33

Nur ein set verwenden. Seine Semantik ist genau das, was Sie wollen: eine Sammlung einzigartiger Elemente.

Technisch werden Sie die Liste zweimal durchlaufen: einmal, um das Set zu erstellen, einmal für Ihre eigentliche Schleife. Aber Sie würden genauso viel Arbeit oder mehr mit jedem anderen Ansatz tun.

+0

mit einem Generator und ein Set wird nur einmal Schleife, werfen Sie einen Blick auf meine Antwort Ich würde Ihre Meinung lieben. @ Eevee – Cherif

3

Der Einfachheit halber: newList = list(set(oldList))

Aber es gibt bessere Möglichkeiten gibt, wenn Sie Geschwindigkeit/Bestellung/Optimierung möchten stattdessen bekommen: ist http://www.peterbe.com/plog/uniqifiers-benchmark

+3

Es gibt keinen guten Grund, um zu einer Liste zurückzukehren. Er hat bereits die Element-Reihenfolge verloren, als es in ein Set umgewandelt wurde, also gibt es keinen Grund, nicht am Set zu bleiben. – ThiefMaster

+0

@ThiefMaster Es gibt Gründe dafür, zu einer Liste zurückzukehren, hauptsächlich Leistung. Listen sind für die Iteration viel schneller als eine Menge, und indem Sie für jedes Element ein internes Attribut beibehalten, können Sie es einfach zurück in eine Liste konvertieren und in die richtige Reihenfolge sortieren. – Flipper

9

set, was Sie wollen, so dass Sie set verwenden sollten . Der Versuch, clever zu sein, bringt subtile Fehler mit sich, wie das Vergessen, eins zu max(mylist) hinzuzufügen! Code defensiv. Machen Sie sich Sorgen darüber, was schneller ist, wenn Sie feststellen, dass es zu langsam ist.

range(min(mylist), max(mylist) + 1) # <-- don't forget to add 1 
+0

Ich würde gerne hier Ihre Meinung zu meiner Antwort ist es schnell, wenn wir mit großen Liste beschäftigen. – Cherif

4

Während ein set sein kann, was Sie Struktur weisen wollen, ist die Frage, was schneller ist. Eine Liste ist schneller. Ihr Beispiel-Code genau vergleichen nicht set vs list, weil Sie aus einer Liste einen Satz inset_loop, sind die Umwandlung und dann sind Sie mit dem Erstellen der list Sie Schleife durch inlist_loop werde. Die Menge und die Liste sollten Sie vor Speicher gebaut und werden von Zeit durchlaufen, und einfach durchgeschleift, um zu sehen, welche Datenstruktur ist schneller bei Iterieren:

ids_list = range(1000000) 
sids_set = set(ids) 
def f(x): 
    for i in x: 
     pass 

%timeit f(ids_set) 
#1 loops, best of 3: 214 ms per loop 
%timeit f(ids_list) 
#1 loops, best of 3: 176 ms per loop 
1

ich die Liste variieren große Schleife zwei Mal darüber wird nehmen Sie viel Zeit und mehr in der zweiten Zeit, die Sie ein Set und nicht eine Liste loopen und wie wir wissen, ist das Iterieren über einen Satz langsamer als Liste.

ich denke, dass Sie die Leistung von generator und set benötigen.

def first_test(): 

    def loop_one_time(my_list): 
     # create a set to keep the items. 
     iterated_items = set() 
     # as we know iterating over list is faster then list. 
     for value in my_list: 
      # as we know checking if element exist in set is very fast not 
      # metter the size of the set. 
      if value not in iterated_items: 
       iterated_items.add(value) # add this item to list 
       yield value 


    mylist = [3,1,5,2,4,4,1,4,2,5,1,3] 

    for v in loop_one_time(mylist):pass 



def second_test(): 
    mylist = [3,1,5,2,4,4,1,4,2,5,1,3] 
    s = set(mylist) 
    for v in s:pass 


import timeit 

print(timeit.timeit('first_test()', setup='from __main__ import first_test', number=10000)) 
print(timeit.timeit('second_test()', setup='from __main__ import second_test', number=10000)) 

heraus gesetzt:

0.024003583388435043 
    0.010424674188938422 

Hinweis: diese Technik, um garantiert

Verwandte Themen