イテラブルのすべての項目を既存のものに追加する「1つの明白な方法」とは何set
ですか?
イテラブルのすべての項目を既存のものに追加する「1つの明白な方法」とは何set
ですか?
回答:
次のようlist
にaの要素をa に追加できますset
。
>>> foo = set(range(0, 4))
>>> foo
set([0, 1, 2, 3])
>>> foo.update(range(2, 6))
>>> foo
set([0, 1, 2, 3, 4, 5])
set
コンストラクターは引数として反復可能オブジェクトを使用するため、その表現を使用すると、インタラクティブセッションに直接貼り付けることができます。
{1, 2, 3}
だったのに対し、Pythonの3でset([1, 2, 3])
のPython 2に
たとえば、aset.add()
ループで行うとパフォーマンスが競合するだろうと信じる人のために、aset.update()
公開する前に信念をすばやくテストする方法の例を次に示します。
>\python27\python -mtimeit -s"it=xrange(10000);a=set(xrange(100))" "a.update(it)"
1000 loops, best of 3: 294 usec per loop
>\python27\python -mtimeit -s"it=xrange(10000);a=set(xrange(100))" "for i in it:a.add(i)"
1000 loops, best of 3: 950 usec per loop
>\python27\python -mtimeit -s"it=xrange(10000);a=set(xrange(100))" "a |= set(it)"
1000 loops, best of 3: 458 usec per loop
>\python27\python -mtimeit -s"it=xrange(20000);a=set(xrange(100))" "a.update(it)"
1000 loops, best of 3: 598 usec per loop
>\python27\python -mtimeit -s"it=xrange(20000);a=set(xrange(100))" "for i in it:a.add(i)"
1000 loops, best of 3: 1.89 msec per loop
>\python27\python -mtimeit -s"it=xrange(20000);a=set(xrange(100))" "a |= set(it)"
1000 loops, best of 3: 891 usec per loop
ループアプローチのアイテムあたりのコストは、update
アプローチの3倍を超えているようです。
使用|= set()
すると約1.5倍のコストがかかりupdate
ますが、ループ内の各アイテムを追加する場合の半分になります。
set()関数を使用して反復可能オブジェクトをセットに変換し、次に標準のセット更新演算子(| =)を使用して、新しいセットの一意の値を既存のセットに追加できます。
>>> a = { 1, 2, 3 }
>>> b = ( 3, 4, 5 )
>>> a |= set(b)
>>> a
set([1, 2, 3, 4, 5])
.update
は、|=
例の演算子のRHSとは異なり、引数が反復可能(必ずしもセットではない)であるという利点があります。
|
ユニオン、&
交差、および^
どちらか一方にあるが両方にはない要素を取得するためのものがあります。しかし、動的に型付けされた言語では、コードを読んだり、飛び回っているオブジェクトのタイプを把握したりすることが難しい場合があるため、これらの演算子を使用することに抵抗があります。それらを認識しない人(またはおそらくPythonがこれらのような演算子を許可していることにさえ気付いていない人)は混乱し、奇妙なビット演算または論理演算が行われていると考えます。これらのオペレーターも他の
.update()
し、ループに個々の要素を追加しました。それ.update()
が速かった。結果をこの既存の回答に追加しました:stackoverflow.com/a/4046249/901641
簡単な更新、Python 3を使用したタイミング:
#!/usr/local/bin python3
from timeit import Timer
a = set(range(1, 100000))
b = list(range(50000, 150000))
def one_by_one(s, l):
for i in l:
s.add(i)
def cast_to_list_and_back(s, l):
s = set(list(s) + l)
def update_set(s,l):
s.update(l)
結果は次のとおりです。
one_by_one 10.184448844986036
cast_to_list_and_back 7.969255169969983
update_set 2.212590195937082
リスト内包表記を使用します。
たとえば、リストを使用してイテラブルの作成を短絡する:)
>>> x = [1, 2, 3, 4]
>>>
>>> k = x.__iter__()
>>> k
<listiterator object at 0x100517490>
>>> l = [y for y in k]
>>> l
[1, 2, 3, 4]
>>>
>>> z = Set([1,2])
>>> z.update(l)
>>> z
set([1, 2, 3, 4])
>>>
[編集:質問の一部を逃した]
for item in items:
extant_set.add(item)
記録として、私は「それを行うには明白な方法が1つ、できれば1つだけあるべきだ」という主張を考えています。偽物です。それは、多くの技術志向の人々が作ること、誰もが同じように考えることを前提としています。ある人にとって明白なことは、別の人にとってはそれほど明白ではありません。
私の提案した解決策は明確に読みやすく、あなたが尋ねたことを実行すると私は主張します。パフォーマンスに影響があるとは思いませんが、何か不足している可能性があります。しかし、それでも、他の開発者にとっては明白でなく好ましい場合もあります。
aset.update(iterable)
に対し、Cの速度でループするポイントがありませんfor item in iterable: aset.add(item)
。