Pythonセットとリスト


回答:


230

それはあなたがそれで何をしようとしているのかに依存します。

セット内にオブジェクトが存在するかどうかを判断する場合、セットは大幅に高速化されます。 x in s)、コンテンツの反復処理はリストよりも低速です。

timeitモジュールを使用して、状況に応じてどちらが速いかを確認できます。


4
あなたの要点:「セットは大幅に高速です」、それを速くする基本的な実装は何ですか?
オーバーエクスチェンジ

スクリプト言語は、基礎となる実装を非表示にするのが好きですが、この明らかな単純さは必ずしも良いことではありません。ソフトウェアを設計するときに、「データ構造」を意識する必要があります。
Christophe Roussy

4
反復中、セットはリストよりも大幅に遅くなることはありません。
omerfarukdogan

38
セットとリストは両方とも線形時間反復を持ちます。一方が他方より「遅い」と言うのは見当違いであり、この答えを読む新しいプログラマーを混乱させました。
habnabit 2018年

@habnabitは、両方とも線形の時間反復があると言っている場合。これは、それらの反復時間が同じであることを意味しますか?違いは何ですか?
Mohammed Noureldin

152

値を繰り返し処理したいだけの場合、リストはセットよりもわずかに高速です。

ただし、アイテムがリストに含まれているかどうかを確認する場合、セットはリストよりもはるかに高速です。ただし、一意のアイテムのみを含めることができます。

タプルは、不変性を除いて、リストとほぼ同じように機能することがわかりました。

反復

>>> def iter_test(iterable):
...     for i in iterable:
...         pass
...
>>> from timeit import timeit
>>> timeit(
...     "iter_test(iterable)",
...     setup="from __main__ import iter_test; iterable = set(range(10000))",
...     number=100000)
12.666952133178711
>>> timeit(
...     "iter_test(iterable)",
...     setup="from __main__ import iter_test; iterable = list(range(10000))",
...     number=100000)
9.917098999023438
>>> timeit(
...     "iter_test(iterable)",
...     setup="from __main__ import iter_test; iterable = tuple(range(10000))",
...     number=100000)
9.865639209747314

オブジェクトが存在するかどうかを確認する

>>> def in_test(iterable):
...     for i in range(1000):
...         if i in iterable:
...             pass
...
>>> from timeit import timeit
>>> timeit(
...     "in_test(iterable)",
...     setup="from __main__ import in_test; iterable = set(range(1000))",
...     number=10000)
0.5591847896575928
>>> timeit(
...     "in_test(iterable)",
...     setup="from __main__ import in_test; iterable = list(range(1000))",
...     number=10000)
50.18339991569519
>>> timeit(
...     "in_test(iterable)",
...     setup="from __main__ import in_test; iterable = tuple(range(1000))",
...     number=10000)
51.597304821014404

6
(初期化セット-> 5.5300979614257812)(初期化リスト-> 1.8846848011016846)(初期化タプル-> 1.8730108737945557)12GB RAMのインテルコアi5クアッドコアのサイズ10,000のアイテムを見つけました。これも考慮する必要があります。
ThePracticalOne 2014

4
オブジェクトの作成を削除するようにコードを更新しました。timeitループのセットアップフェーズは1回だけ呼び出されます(docs.python.org/2/library/timeit.html#timeit.Timer.timeit)。
エリスパーシバル2014

7

リストのパフォーマンス:

>>> import timeit
>>> timeit.timeit(stmt='10**6 in a', setup='a = range(10**6)', number=100000)
0.008128150348026608

セットパフォーマンス:

>>> timeit.timeit(stmt='10**6 in a', setup='a = set(range(10**6))', number=100000)
0.005674857488571661

タプルはリストに似ていますが変更できないため、検討することをお勧めします。メモリの消費量がわずかに少なく、アクセスが高速です。それらは柔軟ではありませんが、リストよりも効率的です。それらの通常の使用は、辞書キーとして機能することです。

セットもシーケンス構造ですが、リストやタプルとは2つの違いがあります。セットには順序がありますが、その順序は任意であり、プログラマーの制御下にはありません。2つ目の違いは、セットの要素は一意でなければならないことです。

set定義により。[ python | wiki ]。

>>> x = set([1, 1, 2, 2, 3, 3])
>>> x
{1, 2, 3}

4
まず、非推奨のライブラリではなく、組み込みのset型リンク(docs.python.org/2/library/stdtypes.html#set)に更新する必要がありsetsます。次に、「セットはシーケンス構造でもあります」と組み込みタイプのリンクから次のように読みます。シーケンスのような動作。」
Seaux 2014

7
rangeはありませんlistrangeカスタム__contains__マジックメソッドを持つ特別なクラスです。
Rine Wang

@RyneWangこれは本当ですが、Python3のみです。Python2では、範囲は通常のリストを返します(そのため、のような恐ろしいことが存在しますxrange
Manoel Vilela

7

Setほぼ瞬時の「包含」チェックによる勝利:https : //en.wikipedia.org/wiki/Hash_table

リストの実装:通常は配列で、金属に近い低レベルで、要素インデックスによる反復とランダムアクセスに適しています。

セットの実装:https : //en.wikipedia.org/wiki/Hash_table、それはリストを反復しませんが、ハッシュを計算することによって要素を見つけます、キーからのをます、それでそれはキー要素とハッシュの性質に依存します関数。dictに使用されるものと同様です。私は疑いlistあなたが非常に少数の要素(<5)を持っている場合は、より大きな要素がより良い数える速くなる可能性setのチェックが含まれているために実行します。要素の追加と削除も高速です。また、セットの作成にはコストがかかることにも常に注意してください。

listが既にソートされている場合、の検索はlistかなり高速になる可能性がありますが、通常の場合、a setは包含チェックの方が高速かつ単純です。


8
金属に近い?Pythonのコンテキストでそれはどういう意味ですか?リストはセットよりメタルにどのように近いですか?
roganjosh

@roganjosh、Pythonはまだマシン上で実行され、「配列」などのリストのようないくつかの実装が近いハードウェアが良いのであるものにしている:stackoverflow.com/questions/176011/...が、それは常にあなたが、それを達成したいのかに依存します抽象化だけでなく、実装についても少し知っておくと便利です。
Christophe Roussy、

2

tl; dr

データ構造(DS)は、基本的に意味するデータの操作を実行するために使用されるため、重要です。入力を受け取り処理し出力を返します。です。。

一部の特定のケースでは、一部のデータ構造が他のデータ構造よりも有用です。したがって、どちらの(DS)がより効率的/高速であるかを尋ねるのはかなり不公平です。ナイフとフォークの間でより効率的なツールを尋ねるようなものです。つまり、すべては状況に依存します。

リスト

リストは変更可能なシーケンスであり通常、同種のアイテムのコレクションを格納するために使用されます

セット

セットオブジェクトは、個別のハッシュ可能なオブジェクトの順序付けられていないコレクションです。これは、メンバーシップをテストし、シーケンスから重複を削除し、交差、和集合、差、対称差などの数学演算を計算するために一般的に使用されます。

使用法

いくつかの回答から、値を繰り返し処理する場合、リストはセットよりもかなり高速であることは明らかです。一方、アイテムがリストに含まれているかどうかを確認する場合、セットはリストよりも高速です。したがって、あなたが言える唯一のことは、リストは特定の操作ではセットよりも優れており、その逆も同様です。


2

値が少数のリテラルの1つであるかどうかをCPythonでチェックするときの結果に興味がありました。setPython 3 vs tupleで勝利しlistor

from timeit import timeit

def in_test1():
  for i in range(1000):
    if i in (314, 628):
      pass

def in_test2():
  for i in range(1000):
    if i in [314, 628]:
      pass

def in_test3():
  for i in range(1000):
    if i in {314, 628}:
      pass

def in_test4():
  for i in range(1000):
    if i == 314 or i == 628:
      pass

print("tuple")
print(timeit("in_test1()", setup="from __main__ import in_test1", number=100000))
print("list")
print(timeit("in_test2()", setup="from __main__ import in_test2", number=100000))
print("set")
print(timeit("in_test3()", setup="from __main__ import in_test3", number=100000))
print("or")
print(timeit("in_test4()", setup="from __main__ import in_test4", number=100000))

出力:

tuple
4.735646052286029
list
4.7308746771886945
set
3.5755991376936436
or
4.687681658193469

3から5のリテラルの場合、setそれでも大きな差で勝ちor、最も遅くなります。

Python 2では、set常に最も遅いです。or2~3リテラルの最速であり、tupleそしてlistより速く4つの以上のリテラルとしています。tuplevs の速度を区別できませんでしたlist

テストする値が、ループ内でリテラルを作成するのではなく、関数のグローバル変数にキャッシュされたset場合、Python 2でも毎回勝ちました。

これらの結果は、Core i7上の64ビットCPythonに適用されます。


0

私は、ユースケースが存在の参照または検索に制限されているSet実装と、ユースケースで反復を実行する必要があるTuple実装をお勧めします。リストは低レベルの実装であり、かなりのメモリオーバーヘッドが必要です。


1
実際、いつセットを使用するかといつタプルを使用するかを適切に区別することは、最も重要です。低レベルのAPIをスクリプト化しない限り、関係するメモリのオーバーヘッドやフットプリントについて心配する必要はありません。

0
from datetime import datetime
listA = range(10000000)
setA = set(listA)
tupA = tuple(listA)
#Source Code

def calc(data, type):
start = datetime.now()
if data in type:
print ""
end = datetime.now()
print end-start

calc(9999, listA)
calc(9999, tupA)
calc(9999, setA)

3つすべての10回の反復を比較した後の出力: 比較


0

セットはより高速であり、2つのセットがあるとしましょう。

set1 = {"Harry Potter", "James Bond", "Iron Man"}
set2 = {"Captain America", "Black Widow", "Hulk", "Harry Potter", "James Bond"}

2つのセットを簡単に結合できます。

set3 = set1.union(set2)

両方に共通するものを見つけます。

set3 = set1.intersection(set2)

両方の違いを確認してください:

set3 = set1.difference(set2)

そして、はるかに!試してみるだけで楽しい!さらに、2つのリスト内の異なる値または2つのリスト内の共通の値を処理する必要がある場合は、リストをセットに変換することを好み、多くのプログラマーがそのようにします。それがあなたを助けることを願っています:-)

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.