2012-05-19 17 views
26

Tôi đã xem qua Python Docs (tôi có thể đã hiểu lầm), nhưng tôi không thấy rằng có một cách để thực hiện việc này (xem bên dưới) mà không cần gọi hàm đệ quy.
Điều tôi muốn làm là tạo ra một giá trị ngẫu nhiên không bao gồm các giá trị ở giữa.Python có thể tạo ra một số ngẫu nhiên không bao gồm một tập hợp các số, mà không sử dụng đệ quy?

Nói cách khác,
Hãy tưởng tượng tôi muốn X là một số ngẫu nhiên đó không phải là trong
range(a - b, a + b)
Tôi có thể làm điều này trên đèo đầu tiên,
hoặc
1. Tôi có phải không ngừng tạo một số,
2. Kiểm tra xem trong số range(),
3. Rửa sạch?

Đối với lý do tại sao tôi không muốn viết một hàm đệ quy,
1. nó cảm thấy như "Tôi không cần phải
2. tập các số liệu mà tôi đang làm điều này cho thực sự có thể kết thúc là khá lớn, và
... Tôi nghe thấy tình trạng tràn ngăn xếp rất tệ, và tôi có thể quá thận trọng khi thực hiện việc này.

Tôi chắc chắn rằng có một cách tốt đẹp, Pythonic, không đệ quy để làm điều đó.

Trả lời

25

Sử dụng random.choice(). Trong ví dụ này, a là giới hạn dưới của bạn, phạm vi giữa b và c bị bỏ qua và d là giới hạn trên của bạn.

import random 
numbers = range(a,b) + range(c,d) 
r = random.choice(numbers) 
+12

Điều này sẽ hoạt động trừ khi tập hợp các câu trả lời có thể là cực kỳ lớn, trong trường hợp đó, nó sẽ sử dụng quá nhiều bộ nhớ và sự cố. –

+0

@AndrewG: Đồng ý, nó không phải là lý tưởng nếu bạn có một phạm vi kích thước của hàng triệu/tỷ. Mặt khác, nó đơn giản và đáng nhớ. Câu trả lời của bạn, trong khi một giải pháp rất tốt đẹp và mạnh mẽ, có thể dễ bị lỗi hơn. – Junuxx

+1

Vâng. Tôi sẽ sử dụng câu trả lời của bạn nếu a, b, c và d đã được biết từ đầu và được biết đến là một tập nhỏ, và của tôi nếu họ phụ thuộc vào đầu vào hoặc được biết đến là một tập hợp lớn. –

4

Giải pháp nhanh nhất sẽ được điều này (với a và b xác định khu vực loại trừ, c và d tập các câu trả lời tốt bao gồm các khu vực loại trừ):

offset = b - a 
maximum = d - offset 
result = random.randrange(c, maximum) 
if result >= a: 
    result += offset 
+0

Hmm, có phải là một lỗi logic trong đó phần cuối của mã - cố gắng để gỡ lỗi nó bây giờ –

+0

... oh. nó phải được bù đắp = b - a. Chỉnh sửa. –

+0

Và nó cũng phải là kết quả> = a. Ở đó, nên làm điều đó. –

6

tôi có thể đã hiểu lầm vấn đề của bạn, nhưng bạn có thể thực hiện điều này mà không đệ quy

def rand(exclude): 
    r = None 
    while r in exclude or r is None: 
     r = random.randrange(1,10) 
    return r 

rand([1,3,9]) 

Mặc dù vậy, bạn vẫn đang Looping trên kết quả cho đến khi bạn tìm thấy những cái mới.

0

Bạn vẫn cần một số phạm vi, nghĩa là giá trị tối thiểu có thể không bao gồm giá trị giữa của bạn.

Tại sao trước tiên bạn không chọn ngẫu nhiên "một nửa" phạm vi bạn muốn, sau đó chọn một số ngẫu nhiên trong phạm vi đó? Ví dụ:

def rand_not_in_range(a,b): 
    rangechoices = ((0,a-b-1),(a+b+1, 10000000)) 
    # Pick a half 
    fromrange = random.choice(rangechoices) 
    # return int from that range 
    return random.randint(*fromrange) 
+2

Điều này sẽ nhận được phân phối 50/50 giữa hai phạm vi, bất kể chúng lớn như thế nào so với nhau. –

9

Một giải pháp có thể là chỉ cần chuyển số ngẫu nhiên ra khỏi phạm vi đó. Ví dụ.

def NormalWORange(a, b, sigma): 
    r = random.normalvariate(a,sigma) 
    if r < a: 
     return r-b 
    else: 
     return r+b 

Điều đó sẽ tạo ra phân bố chuẩn với một lỗ trong phạm vi (a-b, a + b).

Chỉnh sửa: Nếu bạn muốn số nguyên thì bạn sẽ cần thêm một chút công việc. Nếu bạn muốn các số nguyên nằm trong phạm vi [c, a-b] hoặc [a + b, d] thì điều sau đây nên thực hiện thủ thuật.

def RangeWORange(a, b, c, d): 
    r = random.randrange(c,d-2*b) # 2*b because two intervals of length b to exclude 
    if r >= a-b: 
     return r+2*b 
    else: 
     return r 
40

Tạo một số ngẫu nhiên và ánh xạ nó vào phạm vi số bạn muốn.

Nếu bạn muốn tạo ra một số nguyên giữa 1-4 hoặc 7-10, trừ 56, bạn có thể:

  1. Tạo một số nguyên ngẫu nhiên trong phạm vi 1-8
  2. Nếu số ngẫu nhiên lớn hơn 4, thêm 2 vào kết quả.

Việc lập bản đồ trở thành:

Random number: 1 2 3 4 5 6 7 8 
Result:   1 2 3 4 7 8 9 10 

Làm theo cách này, bạn không bao giờ cần phải "tái-roll". Ví dụ trên là số nguyên, nhưng nó cũng có thể được áp dụng cho phao.

+0

+1 để được giải thích tốt - đây là những gì tôi đã nhận được nhưng tôi thấy nó không rõ ràng để giải thích chỉ với mã. –

+3

@AndrewG. : Cảm ơn. :) Nó có thể được giải thích thậm chí tốt hơn với một vài hình ảnh, nhưng năng lượng kích hoạt cho tôi mở Visio là một chút cao tối nay. ;) –

+0

Cảm ơn bạn rất nhiều vì điều này, nó rất thẳng về phía trước trong việc thực hiện và truyền cảm hứng cho người đọc rút ra câu trả lời rõ ràng như trái ngược với mã đơn giản và nói, "Đây, chạy cái này." Cuối cùng tôi đã đi với giải pháp của Junuxx, nhưng tôi cũng đánh giá cao sự thanh lịch của câu trả lời này. –

0

Câu trả lời của Li-aung Yip làm cho vấn đề đệ quy bắt đầu, nhưng tôi phải chỉ ra rằng có thể thực hiện bất kỳ mức độ đệ quy nào mà không phải lo lắng về chồng. Nó được gọi là "đệ quy đuôi". Python không hỗ trợ đuôi đệ quy trực tiếp, vì GVR nghĩ đó là uncool:

http://neopythonic.blogspot.com/2009/04/tail-recursion-elimination.html

Nhưng bạn có thể làm được việc này:

http://paulbutler.org/archives/tail-recursion-in-python/

Tôi tìm thấy nó thú vị mà dính nghĩ rằng đệ quy " cảm thấy sai ". Trong các ngôn ngữ cực kỳ chức năng, chẳng hạn như Scheme, đệ quy là không thể tránh khỏi. Nó cho phép bạn lặp lại mà không tạo các biến trạng thái, mà mô hình lập trình chức năng một cách nghiêm ngặt tránh.

http://www.pling.org.uk/cs/pop.html

+0

Là một người mới lập trình, đây hoàn toàn là thứ tôi cần đọc. Cảm ơn!Tôi không nhất thiết bị dị ứng với đệ quy, và để nói sự thật tôi đã không nhận ra rằng ngay cả BDFL của Python đã tỏ ra khinh thường cho nó nói chung; Tôi chỉ có một cảm giác ruột mà tôi không cần phải sử dụng nó cho dự án cụ thể này. Tôi sẽ không loại trừ nó cho những nỗ lực trong tương lai. –

+0

Xin chào, nếu câu trả lời của tôi hữu ích, vui lòng bỏ phiếu! Tôi cần danh tiếng. –

+0

Tôi nghĩ là tôi có. Lỗi của tôi :) –

Các vấn đề liên quan