109

長さが不明なリストがあり、xそこから1つの要素をランダムにポップして、後でリストに要素が含まれないようにしたいとします。これを行うための最もpythonicな方法は何ですか?

poprandom.randint、およびのかなり不便な組み合わせを使用してそれを行うことができ、lenより短いまたはより良い解決策を見たいと思います。

import random
x = [1,2,3,4,5,6]
x.pop(random.randint(0,len(x)-1))

私が達成しようとしているのは、リストからランダムな要素を連続してポップすることです。(つまり、ある要素をランダムにポップして辞書に移動し、別の要素をランダムにポップして別の辞書に移動する...)

私は Python 2.6 を使用しており、検索機能で解決策が見つからないことに注意してください。

4

9 に答える 9

112

あなたがしているように見えることは、そもそもPythonicに見えません。リストは私が知っているすべての Python 実装で配列として実装されているため、リストの途中から何かを削除しないでください。これはO(n)操作です。

アルゴリズムの一部としてこの機能が本当に必要な場合はblist、途中からの効率的な削除をサポートする のようなデータ構造を確認する必要があります。

純粋な Python では、残りの要素にアクセスする必要がない場合にできることは、最初にリストをシャッフルしてから反復処理することです。

lst = [1,2,3]
random.shuffle(lst)
for x in lst:
  # ...

残りが本当に必要な場合(これは少しコードのにおいがしますが、私見です)、少なくともpop()リストの最後から実行できます (これは高速です!):

while lst:
  x = lst.pop()
  # do something with the element      

一般に、(リストの場合のように) 状態を変更する代わりに、より機能的なスタイルを使用すると、プログラムをよりエレガントに表現できることがよくあります。

于 2012-04-06T19:17:22.770 に答える
60

あなたはそれよりもはるかに良くなることはありませんが、ここにわずかな改善があります:

x.pop(random.randrange(len(x)))

ドキュメントrandom.randrange():

random.randrange([start], stop[, step])
からランダムに選択された要素を返しrange(start, stop, step)ます。これは と同等ですがchoice(range(start, stop, step))、実際には範囲オブジェクトを構築しません。

于 2012-04-06T19:13:22.363 に答える
17

残りのリスト要素の順序が重要でない場合に、リストからランダムなインデックスで1つの要素を削除するには:

import random

L = [1,2,3,4,5,6]
i = random.randrange(len(L)) # get random index
L[i], L[-1] = L[-1], L[i]    # swap with the last element
x = L.pop()                  # pop last element O(1)

スワップは、リストの途中から削除する際のO(n)の動作を回避するために使用されます。

于 2012-12-30T03:45:01.903 に答える
9

別の方法を次に示します。最初にリストをシャッフルしてから、要素がなくなるまで要素のポップを開始してみませんか? このような:

import random

x = [1,2,3,4,5,6]
random.shuffle(x)

while x:
    p = x.pop()
    # do your stuff with p
于 2012-04-06T19:30:20.063 に答える
3

それを行う1つの方法は次のとおりです。

x.remove(random.choice(x))
于 2012-04-06T19:14:55.610 に答える
2

リストからポップしていませんが、重複せずにリストから X 個のランダムなアイテムを取得しようとしているときに、Google でこの質問に遭遇しました。これが私が最終的に使用したものです:

items = [1, 2, 3, 4, 5]
items_needed = 2
from random import shuffle
shuffle(items)
for item in items[:items_needed]:
    print(item)

リスト全体をシャッフルしているが、そのごく一部しか使用していないため、これは少し非効率的かもしれませんが、私は最適化の専門家ではないため、間違っている可能性があります.

于 2013-10-26T09:19:20.540 に答える
1

この回答は@niklas-bの厚意によるものです:

"おそらくpypi.python.org/pypi/blistのようなものを使いたい"

PYPIページを引用するには:

...漸近的なパフォーマンスが向上し、小さなリストで同様のパフォーマンスが得られるリストのような型

blist は Python リストのドロップイン置換であり、大きなリストを変更する際により優れたパフォーマンスを提供します。blist パッケージは、sortedlist、sortedset、weaksortedlist、weaksortedset、sorteddict、および btuple タイプも提供します。

ランダムアクセス/ランダム実行 endは「コピーオンライト」データ構造であるため、パフォーマンスが低下すると考えられます。これは、Python リストの多くのユース ケースの前提に違反するため、注意して使用してください。

ただし、主な使用例がリストで何か奇妙で不自然なことをすることである場合 (@OP によって与えられた強制的な例、または私の Python 2.6 FIFO queue-with-pass-over の問題のように)、これは法案にうまく適合します。 .

于 2016-12-06T23:17:35.763 に答える