it-swarm.com.de

Besser/Schneller durch Satz oder Liste blättern?

Wenn ich eine Python-Liste habe, die viele Duplikate hat und ich jedes Element durchlaufen möchte, aber nicht durch die Duplikate, ist es dann am besten, einen Satz zu verwenden (wie in set(mylist), oder eine andere Möglichkeit zum Erstellen einer Liste ohne Duplikate zu finden? Ich dachte daran, die Liste nur durchzublättern und nach Duplikaten zu suchen, aber ich dachte mir, dass dies set() tut, wenn sie initialisiert wird.

Also, wenn mylist = [3,1,5,2,4,4,1,4,2,5,1,3] und ich wirklich nur durch [1,2,3,4,5] gehen möchte (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 ihrem max-Wert enthält, ich könnte durch range(min(mylist),max(mylist)) oder durch set(mylist) durchlaufen. Sollte ich generell versuchen, das Set in diesem Fall zu vermeiden? Wäre das Finden der Variablen min und max langsamer als nur das Erstellen der Variable set?


Im 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
33
askewchan

Verwenden Sie einfach eine set. Ihre Semantik ist genau das, was Sie wollen: eine Sammlung von Unikaten.

Technisch werden Sie die Liste zweimal durchlaufen: einmal, um den Satz zu erstellen, einmal für Ihre aktuelle Schleife. Aber Sie würden genauso viel oder mehr mit einem anderen Ansatz arbeiten.

37
Eevee

set ist das, was Sie wollen, also sollten Sie set verwenden. Der Versuch, klug zu sein, führt subtile Fehler ein, wie das Vergessen, einen zu max(mylist) hinzuzufügen! Code defensiv. Machen Sie sich Sorgen, was schneller ist, wenn Sie feststellen, dass es zu langsam ist.

range(min(mylist), max(mylist) + 1)  # <-- don't forget to add 1
9
John La Rooy

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

Es gibt jedoch bessere Optionen, wenn Sie stattdessen Geschwindigkeit/Bestellen/Optimierung erhalten möchten: http://www.peterbe.com/plog/uniqifiers-benchmark

5
GordonsBeard

Während eine set das sein kann, was Sie in Bezug auf die Struktur wünschen, ist die Frage, was schneller ist. Eine Liste ist schneller. Ihr Beispielcode kann set nicht mit list genau vergleichen, da Sie von einer Liste in ein Set in set_loop konvertieren und dann die list erstellen, die Sie durch in list_loop durchlaufen. Das Set und die Liste, die Sie durchlaufen, sollten vorab erstellt werden und im Speicher abgelegt werden, um zu sehen, welche Datenstruktur schneller iteriert:

ids_list = range(1000000)
ids_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
5
hamx0r

Die Liste ist sehr unterschiedlich, wenn Sie zwei Mal eine Schleife durchlaufen, wird es viel Zeit in Anspruch nehmen, wenn Sie zum zweiten Mal eine Menge als Schleife durchlaufen.

ich denke, Sie brauchen die Kraft von generator und set.

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))

ausgabe: 

   0.024003583388435043
   0.010424674188938422

Hinweis: Diese Technikreihenfolge ist garantiert

1
EasyOdoo