ทำไม random.shuffle ถึงส่งคืน None?


90

เหตุใดจึงrandom.shuffleกลับมาNoneใน Python

>>> x = ['foo','bar','black','sheep']
>>> from random import shuffle
>>> print shuffle(x)
None

ฉันจะรับค่าสับแทนได้Noneอย่างไร


ไม่ใช่ค่าสุ่ม แต่เป็นการสุ่มรายการแบบสุ่ม
alvas


คำตอบ:


162

random.shuffle()การเปลี่ยนแปลงxรายการในสถานที่

เมธอด Python API ที่เปลี่ยนโครงสร้างแบบแทนที่โดยทั่วไปจะส่งคืนNoneไม่ใช่โครงสร้างข้อมูลที่แก้ไข

หากคุณต้องการสร้างรายการที่สุ่มสับใหม่โดยอิงจากรายการที่มีอยู่ซึ่งรายการที่มีอยู่จะถูกเก็บไว้ตามลำดับคุณสามารถใช้random.sample()กับอินพุตแบบเต็มความยาว:

x = ['foo', 'bar', 'black', 'sheep']
random.sample(x, len(x))     

คุณยังสามารถใช้sorted()กับrandom.random()คีย์การเรียงลำดับ:

shuffled = sorted(x, key=lambda k: random.random())

แต่สิ่งนี้เรียกใช้การเรียงลำดับ (การดำเนินการ O (NlogN)) ในขณะที่การสุ่มตัวอย่างตามความยาวอินพุตจะใช้การดำเนินการ O (N) เท่านั้น (กระบวนการเดียวกับที่random.shuffle()ใช้โดยสลับค่าสุ่มจากพูลที่ลดขนาด)

การสาธิต:

>>> import random
>>> x = ['foo', 'bar', 'black', 'sheep']
>>> random.sample(x, len(x))
['bar', 'sheep', 'black', 'foo']
>>> sorted(x, key=lambda k: random.random())
['sheep', 'foo', 'black', 'bar']
>>> x
['foo', 'bar', 'black', 'sheep']

2
การใช้keyฟังก์ชันสุ่มมูลค่ารับประกันจริงหรือไม่? อัลกอริทึมการเรียงลำดับที่รวดเร็วบางอย่างจะล้มเหลวหากการเปรียบเทียบไม่สอดคล้องกันในตัวเอง ฉันสามารถเห็นการทำงานนี้ได้ทั้งสองวิธีขึ้นอยู่กับการนำไปใช้งาน (การตกแต่ง - จัดเรียง - ไม่ได้รับการตกแต่งจะต้องใช้keyเพียงครั้งเดียวในแต่ละองค์ประกอบจึงจะได้รับการกำหนดไว้อย่างชัดเจน)
torek

2
@torek: Python ใช้ Decorate-sort-undecorate เมื่อจัดเรียงด้วยkeycallable ใช่มันรับประกันได้เนื่องจากแต่ละค่าจะได้รับคีย์สุ่มหนึ่งครั้ง
Martijn Pieters


8

ตามเอกสาร :

สลับลำดับ x ในตำแหน่ง อาร์กิวเมนต์ที่เป็นทางเลือกแบบสุ่มคือฟังก์ชัน 0 อาร์กิวเมนต์ที่ส่งคืนค่าลอยแบบสุ่มใน [0.0, 1.0); ตามค่าเริ่มต้นนี่คือฟังก์ชันสุ่ม ()

>>> x = ['foo','bar','black','sheep']
>>> from random import shuffle
>>> shuffle(x)
>>> x
['bar', 'black', 'sheep', 'foo']

6

ทำไมจริงเหรอ?

1. ประสิทธิภาพ

shuffleแก้ไขรายการในสถานที่ นี่เป็นสิ่งที่ดีเพราะการคัดลอกรายการจำนวนมากจะเป็นค่าใช้จ่ายที่บริสุทธิ์หากคุณไม่ต้องการรายการต้นฉบับอีกต่อไป

2. สไตล์ Pythonic

ตามหลักการ"Explicit is better than implicit"ของpythonic style การกลับรายการจะเป็นความคิดที่ไม่ดีเพราะอาจมีคนคิดว่าเป็นรายการใหม่แม้ว่าในความเป็นจริงจะไม่ใช่ก็ตาม

แต่ฉันไม่ชอบแบบนี้!

หากคุณไม่จำเป็นต้องมีรายการสดคุณจะต้องเขียนสิ่งที่ต้องการ

new_x = list(x)  # make a copy
random.shuffle(new_x)

ซึ่งมีความชัดเจนอย่างยิ่ง หากคุณต้องการสำนวนนี้บ่อยห่อมันในการทำงานshuffled(ดูsorted) new_xผลตอบแทนที่


2

ฉันมีช่วงเวลาที่ดีกับแนวคิดเช่นนี้:

from random import shuffle
x = ['foo','black','sheep'] #original list
y = list(x) # an independent copy of the original
for i in range(5):
    print shuffle(y) # shuffles the original "in place" prints "None" return
    print x,y #prints original, and shuffled independent copy

>>>
None
['foo', 'black', 'sheep'] ['foo', 'black', 'sheep']
None
['foo', 'black', 'sheep'] ['black', 'foo', 'sheep']
None
['foo', 'black', 'sheep'] ['sheep', 'black', 'foo']
None
['foo', 'black', 'sheep'] ['black', 'foo', 'sheep']
None
['foo', 'black', 'sheep'] ['sheep', 'black', 'foo']

เนื่องจาก python ทำ "copy-by-values" โดยค่าเริ่มต้นแทนที่จะเป็น pass-by-reference =) stackoverflow.com/a/986495/610569
alvas

2

Python API ซึ่งเปลี่ยนโครงสร้างแทนตัวเองจะคืนค่าNoneเป็นเอาต์พุต

list = [1,2,3,4,5,6,7,8]
print(list)

เอาต์พุต: [1, 2, 3, 4, 5, 6, 7, 8]

from random import shuffle
print(shuffle(list))

เอาต์พุต: ไม่มี

from random import sample
print(sample(list, len(list)))

เอาต์พุต: [7, 3, 2, 4, 5, 6, 1, 8]


0

คุณสามารถส่งคืนรายการแบบสุ่มโดยใช้random.sample()ตามคำอธิบายของผู้อื่น มันทำงานโดยการสุ่มตัวอย่างองค์ประกอบ k จากรายการโดยไม่ต้องเปลี่ยน ดังนั้นหากมีองค์ประกอบที่ซ้ำกันในรายการของคุณองค์ประกอบเหล่านั้นจะได้รับการปฏิบัติโดยไม่ซ้ำกัน

>>> l = [1,4,5,3,5]
>>> random.sample(l,len(l))
[4, 5, 5, 3, 1]
>>> random.sample(l,len(l)-1)
[4, 1, 5, 3]
>>> random.sample(l,len(l)-1)
[3, 5, 5, 1]
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.