2012-02-12 7 views
17

Khi bạn muốn lặp tuần tự trên một danh sách các số điện thoại bạn sẽ viết:lặp ngẫu nhiên trong Python

for i in range(1000): 
    # do something with i 

Nhưng nếu bạn muốn để lặp qua danh sách các số từ phạm vi (0..999) ngẫu nhiên? Có một nhu cầu (trong mỗi lần lặp) để chọn ngẫu nhiên số không được chọn trong bất kỳ lần lặp trước nào và cần phải lặp qua tất cả các số từ phạm vi (0..999).

Bạn có biết cách thực hiện điều đó (thông minh) không?

Trả lời

23

Bạn có thể sử dụng random.shuffle() tới, tốt, xáo trộn một danh sách:

import random 

r = list(range(1000)) 
random.shuffle(r) 
for i in r: 
    # do something with i 

Bằng cách này, trong nhiều trường hợp bạn muốn sử dụng một vòng lặp for qua một loạt các số nguyên trong ngôn ngữ lập trình khác, bạn có thể mô tả trực tiếp "điều" bạn muốn lặp lại bằng Python.
Ví dụ, nếu bạn muốn sử dụng các giá trị của i để truy cập các yếu tố của một danh sách, bạn nên xáo trộn tốt hơn trong danh sách trực tiếp:

lst = [1970, 1991, 2012] 
random.shuffle(lst) 
for x in lst: 
    print x 

LƯU Ý: Bạn nên chịu cảnh báo sau đây trong tâm trí khi sử dụng random.shuffle() (lấy từ docs:

Lưu ý rằng cho len thậm chí khá nhỏ (x), tổng số hoán vị của x là lớn hơn so với thời gian của hầu hết các số ngẫu nhiên gen erators; điều này ngụ ý rằng hầu hết các hoán vị của một chuỗi dài có thể không bao giờ được tạo ra.

+1

@ Greg: Thực ra tôi nhận thấy rằng random.shuffle đổi các toán hạng tại chỗ, vì vậy tôi thậm chí cant't sử dụng nó như là một biểu:/Cảm ơn đã gợi ý, tuy nhiên, tôi đã thay đổi nó. –

+0

Đừng lo, tôi đã xóa nhận xét của tôi vì nó không còn được áp dụng khi bạn đã thay đổi điều đó. :) –

+3

Ngoài ra, Python sẽ tự động tạo bộ tạo số ngẫu nhiên của nó để không yêu cầu một cuộc gọi đến 'random.seed()'. –

3

Sử dụng phương pháp random.shuffle:

itrange = list(range(100)) 
random.shuffle(itrange) 
for i in itrange: 
    print i 
+1

Để tương lai bằng chứng câu trả lời này, bạn sẽ cần phải sử dụng 'list (range (100))' trong Python 3 vì 'range' trả về một iterator trong 3.x. –

+0

Cảm ơn, nó là chính xác ngay bây giờ. Xin lưu ý rằng đối với các mảng dài không phải tất cả các hoán vị đều có thể: http://docs.python.org/library/random.html#random.shuffle – Gregor

15

Mọi người thường bỏ lỡ cơ hội cho mô-đun hóa. Bạn có thể định nghĩa một hàm để đóng gói ý tưởng "lặp ngẫu nhiên":

def randomly(seq): 
    shuffled = list(seq) 
    random.shuffle(shuffled) 
    return iter(shuffled) 

thì:

for i in randomly(range(1000)): 
    #.. we're good to go .. 
+0

Cảm ơn, đây là con đường để đi. +1 cho khả năng đọc! – shapecatcher

+1

Tò mò: Tại sao trả lại lần thay vì danh sách? – Moberg

+2

Không chắc chắn lý do tại sao tôi trả lại lần lặp. Việc trả lại danh sách cũng sẽ ổn. –

5

Thể hiện phát Python và Fisher–Yates shuffle.

import random 

def shuffled(sequence): 
    deck = list(sequence) 
    while len(deck): 
     i = random.randint(0, len(deck) - 1) # choose random card 
     card = deck[i]      # take the card 
     deck[i] = deck[-1]     # put top card in its place 
     deck.pop()       # remove top card 
     yield card 

Bạn chỉ tạo bao nhiêu số ngẫu nhiên khi bạn sử dụng. Nhưng thành thật mà nói, nó có thể không tiết kiệm được nhiều, vì vậy bạn thường nên sử dụng random.shuffle.

Lưu ý: Nếu thẻ hàng đầu được chọn, deck[i] = deck.pop() sẽ không an toàn, vì vậy hãy xóa phần đầu được thực hiện theo hai bước.

+0

Đây có lẽ là câu trả lời được đánh giá thấp nhất. Những cái khác (bao gồm cả cái được chấp nhận) tất cả đều có thể biến thành một danh sách và trộn nó. Điều này làm việc trong hầu hết các trường hợp (đơn giản), nhưng bộ nhớ không hiệu quả và giết chết chương trình của bạn nếu trình vòng lặp của bạn (rất lớn). Ví dụ, làm việc với các sản phẩm Descartes có danh sách dài là không thể với các giải pháp khác. – Fred

+0

@Fred: Huh? Dòng đầu tiên của giải pháp này là 'deck = list (sequence)'. Bạn có thể có được với lazily xây dựng danh sách, nhưng đó là cùng một thời gian tiệm cận và bộ nhớ như những người khác. Giải pháp này chỉ cho phép bạn tạo ra nhiều số ngẫu nhiên tùy theo nhu cầu của bạn và số ngẫu nhiên rẻ. – leewz

+1

@Fred: Nếu khả năng lặp lại của bạn rất lớn, bạn nên xem xét lùi lại một vài cấp độ. Ví dụ, để có được một tập hợp con nhỏ của một danh sách dài của các danh sách dài (có kích thước đã biết), bạn có thể giả vờ sản phẩm là một danh sách phẳng, sau đó tạo một danh sách ngẫu nhiên các chỉ mục riêng biệt vào danh sách đó theo cách này hay cách khác chuyển đổi thành chỉ mục thành từng danh sách thành phần. Bạn sẽ sử dụng thực tế rằng nguồn là một sản phẩm của danh sách. – leewz

3

Có chức năng random.permutation() trong numpy thực hiện chính xác điều đó cho bạn. Mã của bạn sẽ trông như thế

from numpy.random import permutation 

for i in permutation(1000): 
    # do something with i 
+0

Đừng nhầm lẫn nó với itertools.permutations() mặc dù :) – Moberg