オブジェクトのリストをシャッフルする


770

オブジェクトのリストがあり、それらをシャッフルしたい。私はrandom.shuffleメソッドを使用できると思いましたが、リストがオブジェクトの場合は失敗するようです。オブジェクトをシャッフルする方法、またはこれを回避する別の方法はありますか?

import random

class A:
    foo = "bar"

a1 = a()
a2 = a()
b = [a1, a2]

print(random.shuffle(b))

これは失敗します。


6
失敗の例を挙げていただけますか?random.shuffleは、リスト内のオブジェクトのタイプに関係なく機能するはずです。
バイエル、2009年

3
>>> a1 = a()>>> a2 = a()>>> b = [a1、a2] >>> b [<__ main __。a instance at 0xb7df9e6c>、<__ main __。a instance at 0xb7df9e2c>]> >> print random.shuffle(b)なし
utdiscant

135
後述するように、random.shuffleは新しいシャッフルリストを返しません。リストをその場でシャッフルします。したがって、「print random.shuffle(b)」と言ってはならず、代わりに1行でシャッフルして次の行でbを出力する必要があります。
Eli Courtwright、2009年

派手な配列をシャッフルしようとしている場合は、以下の私の答えを参照してください。
ゴードンビーン

1
元の配列を変更せずに新しいシャッフルされた配列を返すオプションはありますか?
チャーリーパーカー

回答:


1241

random.shuffleうまくいくはずです。オブジェクトがリストである例を次に示します。

from random import shuffle
x = [[i] for i in range(10)]
shuffle(x)

# print(x)  gives  [[9], [2], [7], [0], [4], [5], [3], [1], [8], [6]]
# of course your results will vary

シャッフルは所定の位置で機能、Noneを返すことに注意してください。


1
@seokhoonleeどちらでもない。これは、可能であれば、OSからの実際の乱数のソースによってシードされる、擬似乱数ジェネレーターです。暗号化以外の目的では、ランダムで「十分」です。これは、randomモジュールのドキュメントで詳細に説明されています
dimo414 2016

2
新しいリストにクローンを使用
Mohammad Mahdi KouchakYazdi 2017年

8
元の配列を変更せずに新しいシャッフルされた配列を返すオプションはありますか?
チャーリーパーカー

5
@CharlieParker:私が知っていることではありません。あなたはそれを使用するrandom.sample(x, len(x))か、単にコピーを作成することができますshuffle。以下のためにlist.sortこれと同様の問題があり、今があるのですlist.sortedが、ために同様の変種はありませんshuffle
tom10

6
暗号で保護されたランダム性のための@seokhonlee from random import SystemRandom。代わりに使用してください。cryptorand = SystemRandom()行3を次の行に追加して変更しますcryptorand.shuffle(x)
眉間のある

115

あなたがインプレースシャッフルを学んだように問題がありました。私も頻繁に問題を抱えており、リストのコピー方法も忘れがちです。を使用sample(a, len(a))len(a)て、サンプルサイズとして使用するソリューションです。Pythonのドキュメントについては、https://docs.python.org/3.6/library/random.html#random.sampleを参照してください

以下random.sample()は、シャッフルされた結果を新しいリストとして返すシンプルなバージョンです。

import random

a = range(5)
b = random.sample(a, len(a))
print a, b, "two list same:", a == b
# print: [0, 1, 2, 3, 4] [2, 1, 3, 4, 0] two list same: False

# The function sample allows no duplicates.
# Result can be smaller but not larger than the input.
a = range(555)
b = random.sample(a, len(a))
print "no duplicates:", a == list(set(b))

try:
    random.sample(a, len(a) + 1)
except ValueError as e:
    print "Nope!", e

# print: no duplicates: True
# print: Nope! sample larger than population

元の配列を変更せずに新しいシャッフルされた配列を返すオプションはありますか?
チャーリーパーカー

@CharlieParker:old = [1,2,3,4,5]; new = list(old); random.shuffle(new); print(old); print(new)(replace; newlines)のリストをコピーするだけ
fjsj

old[:]リストの浅いコピーもできますold
Xiao

sample()データ分析のプロトタイピングに特に役立ちます。sample(data, 2)パイプラインのグルーコードを設定し、それを段階的に「最大化」しlen(data)ます。
Katrin Leinweber

58

それを手に入れるのにも少し時間がかかりました。しかし、shuffleのドキュメントは非常に明確です。

リストx シャッフルします。戻り値なし。

だから、すべきではないprint(random.shuffle(b))。代わりにしrandom.shuffle(b)てからprint(b)


44
#!/usr/bin/python3

import random

s=list(range(5))
random.shuffle(s) # << shuffle before print or assignment
print(s)

# print: [2, 4, 1, 3, 0]

31

すでにnumpyを使用している場合(科学および金融アプリケーションで非常に人気があります)、インポートを保存できます。

import numpy as np    
np.random.shuffle(b)
print(b)

http://docs.scipy.org/doc/numpy/reference/generated/numpy.random.shuffle.html


この回答で気に入っているのは、ランダムシードをnumpyで制御できることです。randomモジュールでそれを行う方法があるに違いないが、今のところそれは私には明らかではない...それは私がもっと読む必要があることを意味する。
VanBantam

25
>>> import random
>>> a = ['hi','world','cat','dog']
>>> random.shuffle(a,random.random)
>>> a
['hi', 'cat', 'dog', 'world']

それは私にとってはうまくいきます。必ずランダム方式を設定してください。


それでも動作しません。編集した質問のサンプルコードを参照してください。
utdiscant 2009年

4
2番目のパラメーターのデフォルトはrandom.randomです。省略しても安全です。
cbare

3
@alvas random.shuffle(a)は何も返しません。つまり、Noneを返します。したがって、戻り値ではないことを確認する必要があります。
sonus21

15

複数のリストがある場合は、順列(リストをシャッフルする方法/リスト内の項目を再配置する方法)を最初に定義してから、すべてのリストに適用することができます。

import random

perm = list(range(len(list_one)))
random.shuffle(perm)
list_one = [list_one[index] for index in perm]
list_two = [list_two[index] for index in perm]

Numpy / Scipy

リストが数の多い配列の場合は、より簡単です。

import numpy as np

perm = np.random.permutation(len(list_one))
list_one = list_one[perm]
list_two = list_two[perm]

MPU

mpuconsistent_shuffle機能を持つ小さなユーティリティパッケージを作成しました。

import mpu

# Necessary if you want consistent results
import random
random.seed(8)

# Define example lists
list_one = [1,2,3]
list_two = ['a', 'b', 'c']

# Call the function
list_one, list_two = mpu.consistent_shuffle(list_one, list_two)

mpu.consistent_shuffleは任意の数の引数を取ります。したがって、3つ以上のリストをシャッフルすることもできます。


10
from random import random
my_list = range(10)
shuffled_list = sorted(my_list, key=lambda x: random())

この代替手段は、順序付け関数を入れ替えたい一部のアプリケーションに役立つ場合があります。


また、のおかげでsorted、これは機能的な変更であることに注意してください(そのようなことに夢中になっている場合)。
Inaimathi 2017年

1
Timsortの安定性により、これは値を本当にランダムに分散しません。(同じキーの値は元の順序のままです。)編集:64ビットfloatとの衝突のリスクは非常に小さいため、問題ではないと思います。
Mateen Ulhaq

10

numpy配列を使用random.shuffleする場合、配列内に作成された重複データを使用する場合があります。

代わりにを使用することnumpy.random.shuffleです。すでにnumpyで作業している場合、これはジェネリックよりも推奨される方法random.shuffleです。

numpy.random.shuffle

>>> import numpy as np
>>> import random

使用random.shuffle

>>> foo = np.array([[1,2,3],[4,5,6],[7,8,9]])
>>> foo

array([[1, 2, 3],
       [4, 5, 6],
       [7, 8, 9]])


>>> random.shuffle(foo)
>>> foo

array([[1, 2, 3],
       [1, 2, 3],
       [4, 5, 6]])

使用numpy.random.shuffle

>>> foo = np.array([[1,2,3],[4,5,6],[7,8,9]])
>>> foo

array([[1, 2, 3],
       [4, 5, 6],
       [7, 8, 9]])


>>> np.random.shuffle(foo)
>>> foo

array([[1, 2, 3],
       [7, 8, 9],
       [4, 5, 6]])

1
また、numpy.random.permutation興味深いかもしれません:stackoverflow.com/questions/15474159/shuffle-vs-permute-numpy
Gordon Bean

random.shuffleを使用するときに、配列内に複製されたデータが作成される例はありますか?
ヌレッティン

はい-それは私の答えに含まれています。「例」というタイトルのセクションを参照してください。;)
Gordon Bean

気にしないで、私は3つの要素を見て、それは同じだと思いました。素敵な発見
ヌレティン

1
random.shuffleドキュメントは叫ぶべきですnumpy配列では使用しないでください
Winterlight '13年

10

ワンライナーの場合random.sample(list_to_be_shuffled, length_of_the_list)は、例を使用します。

import random
random.sample(list(range(10)), 10)

出力:[2、9、7、8、3、0、4、1、6、5]


6

'print func(foo)'は、 'foo'で呼び出された場合の 'func'の戻り値を出力します。ただし、 'shuffle'は戻り値の型としてNoneを持ちます。リストが適切に変更されるため、何も出力されません。回避策:

# shuffle the list in place 
random.shuffle(b)

# print it
print(b)

関数型プログラミングスタイルに詳しい場合は、次のラッパー関数を作成することをお勧めします。

def myshuffle(ls):
    random.shuffle(ls)
    return ls

2
これはリストへの参照を渡すため、元のものが変更されます。deepcopy
shivram.ss

@ shivram.ssこの場合、random.sample(ls, len(ls))本当にそのルートを下りたいと思うようなものを望みます。
Arda Xi

4

shuffledsortvs と同じ意味でsorted)呼び出される関数を定義することができます

def shuffled(x):
    import random
    y = x[:]
    random.shuffle(y)
    return y

x = shuffled([1, 2, 3, 4])
print x

3
import random

class a:
    foo = "bar"

a1 = a()
a2 = a()
a3 = a()
a4 = a()
b = [a1,a2,a3,a4]

random.shuffle(b)
print(b)

shuffle が配置されているので、結果ではNoneなく、リストを出力します。


1

あなたはこれのために行くことができます:

>>> A = ['r','a','n','d','o','m']
>>> B = [1,2,3,4,5,6]
>>> import random
>>> random.sample(A+B, len(A+B))
[3, 'r', 4, 'n', 6, 5, 'm', 2, 1, 'a', 'o', 'd']

2つのリストに戻りたい場合は、この長いリストを2つに分割します。


1

リストをパラメーターとして取り、シャッフルされたバージョンのリストを返す関数を作成できます。

from random import *

def listshuffler(inputlist):
    for i in range(len(inputlist)):
        swap = randint(0,len(inputlist)-1)
        temp = inputlist[swap]
        inputlist[swap] = inputlist[i]
        inputlist[i] = temp
    return inputlist

1
""" to shuffle random, set random= True """

def shuffle(x,random=False):
     shuffled = []
     ma = x
     if random == True:
         rando = [ma[i] for i in np.random.randint(0,len(ma),len(ma))]
         return rando
     if random == False:
          for i in range(len(ma)):
          ave = len(ma)//3
          if i < ave:
             shuffled.append(ma[i+ave])
          else:
             shuffled.append(ma[i-ave])    
     return shuffled

小さな紹介や説明が役に立ちますか?
kacase

この関数は、アクティビティをシャッフルするのに役立ちます。数値のリストを3回シャッフルする必要があり、3回ランダムシャッフルを実行する必要がある場合、ランダム性をTrueに設定し、ランダム性を必要としない場合は、保存する順序を同じにして、変更を行わず、コードを実行するだけです。
ジョシュ・アニッシュ

この関数の呼び出し元が実行時にランダムまたは非ランダムのどちらのシャッフルを必要とするかを決定するユースケースはないため、この関数は2つに分割する必要があります。
toolforger 2018年

非ランダムシャッフルが何をすることになっているのか説明はありません。(正接では、答えではないので質問なので、スタックオーバーフローの目的を果たしません。)
toolforger

1

シャッフルまたはサンプルを使用できます。どちらもランダムモジュールから取得されます。

import random
def shuffle(arr1):
    n=len(arr1)
    b=random.sample(arr1,n)
    return b

または

import random
def shuffle(arr1):
    random.shuffle(arr1)
    return arr1

0

ソースファイルにrandom.pyという名前を付けていないこと、および作業ディレクトリにrandom.pycというファイルがないことを確認してください。プログラムがpythons randomモジュールの代わりにローカルのrandom.pyファイルをインポートしようとする可能性があります。 。


0
def shuffle(_list):
    if not _list == []:
        import random
        list2 = []
        while _list != []:
            card = random.choice(_list)
            _list.remove(card)
            list2.append(card)
        while list2 != []:
            card1 = list2[0]
            list2.remove(card1)
            _list.append(card1)
        return _list

この関数は、ランダムモジュールを使用したくない場合に役立ちます
Pogramist

このソリューションは冗長であるだけでなく非効率的です(実行時間はリストサイズの2乗に比例します)。
toolforger 2018年

2番目のループ_list.extend(list2)は、より簡潔で効率的なに置き換えることができます。
toolforger 2018年

パラメータを変更するPython関数が結果を返すことはありません。これは単なる慣例ですが、便利なものです。多くの場合、呼び出すすべての関数の実装を確認する時間が足りないため、関数の名前を見ただけで結果が得られた人は、その関数を見ると非常に驚きます。パラメータを更新します。
toolforger 2018年

0
import random
class a:
    foo = "bar"

a1 = a()
a2 = a()
b = [a1.foo,a2.foo]
random.shuffle(b)

-1

シャッフル処理は「交換有り」のため、商品ごとに発生頻度が変わる場合がございます!少なくとも、リストのアイテムがリストに含まれている場合。

例えば、

ml = [[0], [1]] * 10

あと、

random.shuffle(ml)

[0]の数は9または8ですが、正確に10ではありません。


-1

計画:重い作業を行うためにライブラリに依存せずにシャッフルを書き出します。例:要素0で始まるリストを最初から調べます。そのための新しいランダムな位置を見つけます。たとえば、6に0の値を6に入れ、6の値を0に入れます。要素1に移動し、このプロセスを繰り返して、残りのリストを繰り返します。

import random
iteration = random.randint(2, 100)
temp_var = 0
while iteration > 0:

    for i in range(1, len(my_list)): # have to use range with len()
        for j in range(1, len(my_list) - i):
            # Using temp_var as my place holder so I don't lose values
            temp_var = my_list[i]
            my_list[i] = my_list[j]
            my_list[j] = temp_var

        iteration -= 1

あなたはこのようなPythonで変数を入れ替えることができます:my_list[i], my_list[j] = my_list[j], my_list[i]
Karolis Ryselis

-2

正常に動作します。私はここで関数をリストオブジェクトとして試してみました:

    from random import shuffle

    def foo1():
        print "foo1",

    def foo2():
        print "foo2",

    def foo3():
        print "foo3",

    A=[foo1,foo2,foo3]

    for x in A:
        x()

    print "\r"

    shuffle(A)
    for y in A:
        y()

次のように出力します:foo1 foo2 foo3 foo2 foo3 foo1(最後の行のfooの順序はランダムです)

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