2013-02-27 6 views
28

多くの重複があるpythonリストを持っていて、各アイテムを繰り返し処理したいが、重複を経由しない場合は、(set(mylist)のように)セットを使用するのが最善か、だから、重複?私はリストをループして、重複をチェックすることを考えていましたが、私はそれはそれが初期化されますときset()が何をするかだ考え出し。セットやリストをループスルーする方が良い/もっと速い?

mylist = [3,1,5,2,4,4,1,4,2,5,1,3]場合、私は実際には(順番は関係ありません)[1,2,3,4,5]をループにしたいです、 set(mylist)などを使用する必要がありますか?

最後の例では、minとmの間のすべての整数がリストに含まれています私はrange(min(mylist),max(mylist))またはset(mylist)を通してループすることができます。私は一般的にこの場合にsetを使わないようにするべきですか?またsetを作成するよりも、minmaxの方が遅いでしょうか?最後の例の場合


setは速いです:

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

なぜそれをテストしないと保証されているの? –

+2

@JoelCornett done :) – askewchan

+0

これまでに書いたプログラムでこの速度差が実際に問題になると思いますか? 'numpy'で物事を守り、反復するために百万要素の' list'を構築するのではなくgenexpを使います(Py2の場合は 'range'の代わりに' xrange'を使います)。代わりにCでタイトなループをしようとします(例えば、同じことをする 'for'ループの代わりに' idlist = range(...) 'など)などはすべて、より大きな違いをもたらすでしょう。 – abarnert

答えて

33

ちょうどsetを使用しています。そのセマンティクスは、あなたが欲しいものです:ユニークなアイテムのコレクション。

技術的には、リストを2回繰り返します.1回は実際のループに1回、セットを作成するには1回です。しかし、あなたは他の方法と同じくらい多くの仕事をしています。簡単のため

+0

ジェネレータとセットを使用すると1回だけループします。あなたの意見が大好きな私の答えを見てください。@ Eevee – Cherif

3

newList = list(set(oldList))

しかし、あなたの代わりにスピード/発注/最適化を取得したい場合は、より良い選択肢がそこにあります:あなたはsetを使用する必要がありますのでhttp://www.peterbe.com/plog/uniqifiers-benchmark

+3

リストに戻る理由はありません。彼は既にセットに変換するときに要素の順序を失ってしまったので、セットにとどまっていない理由はありません。 – ThiefMaster

+0

@ThiefMasterリストに戻ることを望む理由は、主にパフォーマンスです。リストは、繰り返しよりもセットの方がはるかに高速で、各要素の内部属性を保持することで、簡単にリストに戻って適切な順序にソートすることができます。 – Flipper

9

setは、あなたが望むものです。巧妙にしようとすると、max(mylist)に1つを追加するのを忘れるような微妙なバグが導入されます!コードは防衛的です。あなたがそれが遅すぎると判断した場合、速いものについて心配してください。

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

私は大きいリストを扱う速いwheである私の答えのあなたの意見をここに愛する。 – Cherif

4

setあなたは構造単位の望むものかもしれないが、問題はより高速であることです。リストはより速いです。あなたはset_loopにセットにリストから変換している、そしてあなたはlist_loopをループすることがありますlistを作成しているので、あなたのコード例では、正確にlistsetを比較しません。セットとあなたはを反復処理リストが構築され、メモリ内に事前に、単に反復処理で高速化しているデータ構造を参照するためにループスルーする必要があります。

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

を、私は、リストがその上に大きなループ2時間を変更されますあなたがリストではなくセットをループしている2回目に多くの時間を費やしてください、そして、私たちが知っているように、セット上の反復はリストより遅いです。

あなたは、generatorsetの力が必要だと思います。

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

出す:

0.024003583388435043 
    0.010424674188938422 

注:この技術順は

関連する問題