สลับรายการของวัตถุ


770

ฉันมีรายการสิ่งของและต้องการสับเปลี่ยน ฉันคิดว่าฉันสามารถใช้random.shuffleวิธีการได้ แต่ดูเหมือนว่าจะล้มเหลวเมื่อรายการเป็นวัตถุ มีวิธีการสับวัตถุหรือวิธีอื่นรอบนี้?

import random

class A:
    foo = "bar"

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

print(random.shuffle(b))

สิ่งนี้จะล้มเหลว


6
คุณยกตัวอย่างว่ามันล้มเหลวได้ไหม? random.shuffle ควรทำงานกับประเภทของวัตถุในรายการไม่เปลี่ยนแปลง
bayer

3
>>> a1 = a () >>> a2 = a () >>> b = [a1, a2] >>> b [<__ main __. อินสแตนซ์ที่ 0xb7df9e6c>, <__ main __. อินสแตนซ์ที่ 0xb7df9e2c>]> >> พิมพ์แบบ
สุ่มสลับ

135
ตามที่ระบุไว้ด้านล่าง random.shuffle จะไม่ส่งรายการสับเปลี่ยนใหม่ มันสลับรายการในสถานที่ ดังนั้นคุณไม่ควรพูดว่า "print random.shuffle (b)" และควรทำการสับเปลี่ยนในหนึ่งบรรทัดและพิมพ์ b ในบรรทัดถัดไปแทน
Eli Courtwright

หากคุณพยายามที่จะสับเปลี่ยนอาร์เรย์ numpy ดูคำตอบของฉันด้านล่าง
Gordon Bean

1
มีตัวเลือกที่ไม่กลายพันธุ์อาร์เรย์เดิม แต่ส่งกลับอาร์เรย์แบบสับใหม่หรือไม่
Charlie Parker

คำตอบ:


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

โปรดทราบว่าการสับเปลี่ยนการทำงานในสถานที่และผลตอบแทนที่ไม่มี


1
@ seokhoonlee ไม่เหมือนกัน มันเป็นตัวสร้างตัวเลขแบบสุ่ม pseduo ซึ่งเมื่อเป็นไปได้จะถูก seeded โดยแหล่งที่มาของการสุ่มที่แท้จริงจากระบบปฏิบัติการ สำหรับวัตถุประสงค์ทั้งหมดยกเว้นการเข้ารหัสนั้นเป็นการสุ่ม "เพียงพอ" นี้จะออกมาวางในรายละเอียดในเอกสารของโมดูลrandom
dimo414

2
ใช้โคลนสำหรับรายการใหม่
Mohammad Mahdi KouchakYazdi

8
มีตัวเลือกที่ไม่กลายพันธุ์อาร์เรย์เดิม แต่ส่งกลับอาร์เรย์แบบสับใหม่หรือไม่
Charlie Parker

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)เป็นขนาดตัวอย่าง ดูhttps://docs.python.org/3.6/library/random.html#random.sampleสำหรับเอกสาร Python

ต่อไปนี้เป็นรุ่นที่ใช้งานง่าย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

มีตัวเลือกที่ไม่กลายพันธุ์อาร์เรย์เดิม แต่ส่งกลับอาร์เรย์แบบสับใหม่หรือไม่
Charlie Parker

เพียงแค่คัดลอกรายการ @CharlieParker: old = [1,2,3,4,5]; new = list(old); random.shuffle(new); print(old); print(new)(แทนที่; ด้วย newlines)
fjsj

old[:]oldนอกจากนี้ยังสามารถทำสำเนาตื้นสำหรับรายชื่อ
เซี่ยว

sample()มีประโยชน์อย่างยิ่งสำหรับการสร้างต้นแบบการวิเคราะห์ข้อมูล sample(data, 2)สำหรับการตั้งค่ารหัสกาวของท่อแล้ว "ขยับขยาย" len(data)มันทีฉลาดขึ้นไป
Katrin Leinweber

58

ฉันใช้เวลาพอสมควรแล้ว แต่เอกสารสำหรับการสับเปลี่ยนมีความชัดเจนมาก:

สลับรายการ x เข้าที่ ; กลับไม่มี

print(random.shuffle(b))ดังนั้นคุณจึงไม่ควร แต่ทำแล้วrandom.shuffle(b)print(b)



31

หากคุณกำลังใช้งาน numpy อยู่แล้ว (เป็นที่นิยมอย่างมากสำหรับการใช้งานด้านวิทยาศาสตร์และการเงิน) คุณสามารถบันทึกการนำเข้าได้

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

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


สิ่งที่ฉันชอบเกี่ยวกับคำตอบนี้คือฉันสามารถควบคุมเมล็ดแบบสุ่มในจำนวนที่กำหนด ฉันเดิมพันว่ามีวิธีการทำเช่นนั้นในโมดูลสุ่ม แต่ไม่ชัดเจนสำหรับฉันตอนนี้ ... ซึ่งหมายความว่าฉันต้องอ่านเพิ่มเติม
VanBantam

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

มันใช้งานได้ดีสำหรับฉัน ตรวจสอบให้แน่ใจว่าตั้งค่าวิธีการสุ่ม


ยังใช้งานไม่ได้สำหรับฉันดูรหัสตัวอย่างในคำถามที่แก้ไข
utdiscant

4
พารามิเตอร์ที่สองมีค่าเริ่มต้นเป็น 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

ถ้ารายการของคุณเป็นอาร์เรย์ numpy มันง่ายกว่า:

import numpy as np

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

MPU

ฉันได้สร้างแพ็คเกจอรรถประโยชน์ขนาดเล็กmpuที่มีconsistent_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ใช้จำนวนอาร์กิวเมนต์โดยพลการ ดังนั้นคุณสามารถสลับรายการได้สามรายการขึ้นไป


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

ทางเลือกนี้อาจมีประโยชน์สำหรับบางแอปพลิเคชันที่คุณต้องการสลับฟังก์ชันการสั่งซื้อ


นอกจากนี้โปรดทราบว่าต้องขอบคุณsortedนี่คือการสลับการทำงาน (หากคุณเป็นสิ่งนั้น)
Inaimathi

1
สิ่งนี้ไม่ได้กระจายค่าแบบสุ่มอย่างแท้จริงเนื่องจากความเสถียรของ Timsort (ค่าที่มีรหัสเดิมจะอยู่ในลำดับเดิม) แก้ไข: ฉันคิดว่ามันไม่สำคัญเนื่องจากความเสี่ยงของการชนกับ 64- บิตลอยค่อนข้างน้อย
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

ไม่เป็นไรฉันเห็นองค์ประกอบสามอย่างและคิดว่ามันเหมือนกัน Nice find
nurettin

1
random.shuffleเอกสารควรตะโกนห้ามใช้กับอาร์เรย์ที่มีจำนวนมาก
winterlight

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)' จะพิมพ์ค่าตอบแทนของ 'func' เมื่อเรียกด้วย 'foo' 'สลับ' อย่างไรก็ตามไม่มี None เป็นประเภทส่งคืนเนื่องจากจะมีการแก้ไขรายการจึงไม่พิมพ์อะไรเลย การแก้ปัญหา:

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

# print it
print(b)

หากคุณมีสไตล์การเขียนโปรแกรมที่ใช้งานได้มากขึ้นคุณอาจต้องการใช้ฟังก์ชัน wrapper ต่อไปนี้:

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

2
ตั้งแต่นี้ผ่านการอ้างอิงถึงรายการต้นฉบับได้รับการแก้ไข คุณอาจต้องการคัดลอกรายการก่อนที่จะสับโดยใช้deepcopy
shivram.ss

@ shivram.ss ในกรณีนี้คุณต้องการอะไรแบบนั้นrandom.sample(ls, len(ls))ถ้าคุณอยากลงเส้นทางนั้นจริงๆ
Arda Xi

4

สามารถกำหนดฟังก์ชั่นที่เรียกว่าshuffled(ในความหมายเดียวกันsortกับ vs 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']

หากคุณต้องการกลับไปที่สองรายการคุณจะต้องแยกรายการยาวนี้ออกเป็นสองรายการ


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

ฟังก์ชั่นนี้มีประโยชน์สำหรับกิจกรรมการสับภาพสมมติว่าคุณต้องสลับรายการตัวเลขสามครั้งและในสามครั้งคุณต้องสุ่มแบบสุ่มเพื่อให้เกิดขึ้นจากนั้นเพียงแค่เปลี่ยนอาร์กิวเมนต์แบบสุ่มเป็น True อย่างอื่นถ้าคุณไม่ต้องการแบบสุ่มและคุณต้องการ เพื่อการสับแบบเดียวกันที่จะรักษาไว้แล้วไม่ทำการเปลี่ยนแปลงใด ๆ เพียงแค่เรียกใช้รหัส
Josh Anish

เนื่องจากไม่มีกรณีการใช้งานที่ผู้เรียกฟังก์ชั่นนี้จะตัดสินใจที่รันไทม์ไม่ว่าเขาต้องการสุ่มหรือไม่สุ่มสับเปลี่ยนฟังก์ชั่นนี้ควรแบ่งออกเป็นสอง
toolforger

ไม่มีคำอธิบายว่าควรทำแบบสุ่มแบบสุ่มอย่างไร (บนแทนเจนต์ไม่ใช่คำตอบดังนั้นจึงไม่ตอบสนองวัตถุประสงค์ของ Stack Overflow)
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 .. อาจทำให้โปรแกรมของคุณลองและนำเข้าไฟล์ random.py ในเครื่องของคุณแทนโมดูลสุ่ม pythons .


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

โซลูชันนี้ไม่เพียง แต่ verbose แต่ไม่มีประสิทธิภาพ (runtime เป็นสัดส่วนกับกำลังสองของขนาดรายการ)
toolforger

สามารถแทนที่ลูปที่สองได้_list.extend(list2)ซึ่งสั้นกว่าและมีประสิทธิภาพมากกว่า
toolforger

ฟังก์ชัน Python ที่แก้ไขพารามิเตอร์ไม่ควรส่งคืนผลลัพธ์ มันเป็นเพียงแค่การประชุม แต่ก็มีประโยชน์: คนมักจะไม่มีเวลาดูการใช้งานฟังก์ชั่นทั้งหมดที่พวกเขาเรียกดังนั้นใครก็ตามที่เพิ่งเห็นชื่อฟังก์ชั่นของคุณและมันมีผลจะแปลกใจมากที่เห็นฟังก์ชั่น อัพเดตพารามิเตอร์
toolforger


-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

คุณสามารถสลับตัวแปรเป็นไพ ธ อนได้เช่นนี้: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 (foos ในแถวสุดท้ายมีลำดับแบบสุ่ม)

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.