Metody interfejsu API języka Python, które zmieniają strukturę lokalnie, generalnie zwracają None, a nie zmodyfikowaną strukturę danych.
Jeśli chcesz utworzyć nową losowo odtwarzaną listę na podstawie istniejącej, gdzie istniejąca lista jest utrzymywana w porządku, możesz użyć random.sample()z pełną długością danych wejściowych:
x = ['foo', 'bar', 'black', 'sheep']
random.sample(x, len(x))
ale to wywołuje sortowanie (operacja O (NlogN)), podczas gdy próbkowanie do długości wejściowej wymaga tylko operacji O (N) (ten sam proces, który random.shuffle()jest używany, zastępując losowe wartości z kurczącej się puli).
Czy korzystanie z keyfunkcji o wartości losowej jest naprawdę gwarantowane? Niektóre algorytmy szybkiego sortowania zawodzą, jeśli porównania nie są spójne. Widzę, że działa to w obie strony, w zależności od implementacji (dekorowanie-sortowanie-undecorate będzie musiało zostać zastosowane keytylko raz na każdym elemencie, więc będzie dobrze zdefiniowane).
torek
2
@torek: Python używa decorate-sort-undecorate podczas sortowania z możliwością keywywołania. Więc tak, jest to gwarantowane, ponieważ każda wartość otrzymuje swój losowy klucz dokładnie raz.
Martijn Pieters
35
Ta metoda też działa.
import random
shuffled = random.sample(original, len(original))
Potasuj sekwencję x na miejscu. Opcjonalny argument random to 0-argumentowa funkcja zwracająca losową liczbę zmiennoprzecinkową z wartości [0.0, 1.0); domyślnie jest to funkcja random ().
>>> x = ['foo','bar','black','sheep']
>>> from random import shuffle
>>> shuffle(x)
>>> x
['bar', 'black', 'sheep', 'foo']
shufflemodyfikuje listę w miejscu. To jest miłe, ponieważ kopiowanie dużej listy byłoby czystym kosztem, jeśli nie potrzebujesz już oryginalnej listy.
2. Styl Pythonic
Zgodnie z zasadą stylu pythonowego „wyraźne jest lepsze niż niejawne” , zwrócenie listy byłoby złym pomysłem, ponieważ wówczas można by pomyśleć, że jest to nowa, chociaż w rzeczywistości tak nie jest.
Ale mi się to nie podoba!
Jeśli nie potrzebujesz nową listę, trzeba będzie napisać coś podobnego
new_x = list(x) # make a copy
random.shuffle(new_x)
co jest ładnie wyraźne. Jeśli często potrzebujesz tego idiomu, zawiń go w funkcję shuffled(zobacz sorted), która zwraca new_x.
Możesz zwrócić potasowaną listę, korzystając z random.sample()wyjaśnień innych. Działa na zasadzie próbkowania k elementów z listy bez zastępowania . Jeśli więc na liście znajdują się zduplikowane elementy, zostaną one potraktowane wyjątkowo.
Odpowiedzi:
random.shuffle()
zmieniax
listę na miejscu .Metody interfejsu API języka Python, które zmieniają strukturę lokalnie, generalnie zwracają
None
, a nie zmodyfikowaną strukturę danych.Jeśli chcesz utworzyć nową losowo odtwarzaną listę na podstawie istniejącej, gdzie istniejąca lista jest utrzymywana w porządku, możesz użyć
random.sample()
z pełną długością danych wejściowych:x = ['foo', 'bar', 'black', 'sheep'] random.sample(x, len(x))
Możesz również użyć
sorted()
zrandom.random()
jako klucz sortowania:shuffled = sorted(x, key=lambda k: random.random())
ale to wywołuje sortowanie (operacja O (NlogN)), podczas gdy próbkowanie do długości wejściowej wymaga tylko operacji O (N) (ten sam proces, który
random.shuffle()
jest używany, zastępując losowe wartości z kurczącej się puli).Próbny:
>>> 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']
źródło
key
funkcji o wartości losowej jest naprawdę gwarantowane? Niektóre algorytmy szybkiego sortowania zawodzą, jeśli porównania nie są spójne. Widzę, że działa to w obie strony, w zależności od implementacji (dekorowanie-sortowanie-undecorate będzie musiało zostać zastosowanekey
tylko raz na każdym elemencie, więc będzie dobrze zdefiniowane).key
wywołania. Więc tak, jest to gwarantowane, ponieważ każda wartość otrzymuje swój losowy klucz dokładnie raz.Ta metoda też działa.
import random shuffled = random.sample(original, len(original))
źródło
Według dokumentów :
>>> x = ['foo','bar','black','sheep'] >>> from random import shuffle >>> shuffle(x) >>> x ['bar', 'black', 'sheep', 'foo']
źródło
Dlaczego tak naprawdę?
1. Wydajność
shuffle
modyfikuje listę w miejscu. To jest miłe, ponieważ kopiowanie dużej listy byłoby czystym kosztem, jeśli nie potrzebujesz już oryginalnej listy.2. Styl Pythonic
Zgodnie z zasadą stylu pythonowego „wyraźne jest lepsze niż niejawne” , zwrócenie listy byłoby złym pomysłem, ponieważ wówczas można by pomyśleć, że jest to nowa, chociaż w rzeczywistości tak nie jest.
Ale mi się to nie podoba!
Jeśli nie potrzebujesz nową listę, trzeba będzie napisać coś podobnego
new_x = list(x) # make a copy random.shuffle(new_x)
co jest ładnie wyraźne. Jeśli często potrzebujesz tego idiomu, zawiń go w funkcję
shuffled
(zobaczsorted
), która zwracanew_x
.źródło
Miałem chwilę aha z taką koncepcją:
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']
źródło
Pythonowe API, które zmieniają strukturę, same zwracają None jako dane wyjściowe.
list = [1,2,3,4,5,6,7,8] print(list)
Wyjście: [1, 2, 3, 4, 5, 6, 7, 8]
from random import shuffle print(shuffle(list))
Wyjście: brak
from random import sample print(sample(list, len(list)))
Wyjście: [7, 3, 2, 4, 5, 6, 1, 8]
źródło
Możesz zwrócić potasowaną listę, korzystając z
random.sample()
wyjaśnień innych. Działa na zasadzie próbkowania k elementów z listy bez zastępowania . Jeśli więc na liście znajdują się zduplikowane elementy, zostaną one potraktowane wyjątkowo.>>> 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]
źródło