2016-03-03 19 views
5

Tôi gặp vấn đề với việc ngẫu nhiên danh sách với các hạn chế trong Python (3). Tôi đã nhìn thấy một số câu hỏi khác liên quan đến điều này, nhưng không ai trong số họ thực sự dường như giải quyết vấn đề của tôi. Tôi là người mới bắt đầu, vì vậy mọi trợ giúp đều được đánh giá cao!xáo trộn danh sách với các hạn chế trong Python

Tôi đang thiết kế một thử nghiệm sử dụng hai loại kích thích: hình dạng và màu sắc (bốn trong số mỗi loại). Tôi cần phải tạo ra hoán vị của tất cả 16 kết hợp, mà tôi đã thực hiện với random.shuffle-function:

import random 

# letters are shapes, numbers are colors 
x=["a1","a2","a3","a4","b1","b2","b3","b4","c1","c2","c3","c4","d1","d2","d3","d4"] 

random.shuffle(x) 

Cho đến nay rất tốt. Tuy nhiên, tôi muốn tránh hình dạng (chữ cái) hoặc màu (số) xuất hiện hai lần liên tiếp trong kết quả của tôi (ví dụ: "a2" theo sau là "a4" hoặc "c2" theo sau là "a2").

Có cách nào để hạn chế như vậy không?
Cảm ơn bạn trước!

+3

Cho đến nay tốt như vậy? 'random.shuffle (x)' trả về None vì nó xáo trộn 'x' tại chỗ. Do đó, 'kết quả' sẽ là Không. – zondo

+0

Điều này có vẻ giống như một vấn đề đồ thị. Mỗi nút có một cạnh trỏ đến tất cả các nút khác ngoại trừ các nút có cùng hình dạng hoặc màu sắc (vì vậy (n-1)^2 cạnh trên mỗi nút). Và sau đó bạn muốn có một con đường ngẫu nhiên chạm vào mọi đỉnh chính xác một lần - một con đường Hamilton tôi nghĩ. –

+0

@zondo Ồ đúng, cảm ơn vì đã chỉ ra điều đó. Tôi đã sửa lại ví dụ. – Frederik

Trả lời

1

Something như thế này nên đưa ra một câu trả lời hợp lý trong một thời gian hợp lý

import random 
while 1: 
    choices = ["a1", "a2","a3","b1","b2","b3","c1","c2","c3"] 

    shuffle = [] 

    last = "" 

    while choices: 
     l = choices 
     if last: 
      l = [x for x in l if x[0] != last[0] and x[1] != last[1]] 
     if not l: 
      #no valid solution 
      break 
     newEl = random.choice(l) 
     last = newEl 
     shuffle.append(newEl) 
     choices.remove(newEl) 
    if not choices: 
     print(shuffle) 
     break 
+0

Cảm ơn các downvote ;-) nếu bạn có một giải pháp tốt hơn, bạn được tự do để cho bạn biết –

+1

Tôi tò mò về downvote quá. Tôi đã thử giải pháp của bạn và có vẻ như nó hoạt động. –

+0

Tôi kiểm tra mã trước khi tôi giao nó ;-) –

4

Một cách để xử lý điều này có thể là có hai danh sách một trong các hình dạng và một trong các màu. Phát ngẫu nhiên từng danh sách. Bây giờ trộn lẫn hai danh sách. Vì mỗi danh sách được tạo ngẫu nhiên, danh sách hỗn hợp cũng ngẫu nhiên nhưng bạn không có hai mục nhập nào cùng nhau.

Lưu ý rằng khi sử dụng mã zip, bạn sẽ thực sự nhận được các cặp sẽ cho phép bạn xử lý kiểm tra của mình bằng cách lấy từng cặp từ kết quả.

Trong trường hợp đặc biệt này mỗi màu là thành viên của các hình dạng danh sách trong khi mỗi màu sắc là một thành viên của danh sách các màu sắc

shapes = ['a', 'b', 'c', 'd'] 
colors = ['1', '2', '3', '4'] 
zip(shapes, colors) 
[('a', '1'), ('b', '2'), ('c', '3'), ('d', '4')] 

này cho chúng ta mỗi ngẫu nhiên cá nhân chứ không phải là tạo ra tất cả 16 khả năng cùng một lúc và sau đó xáo trộn chúng. Điều này có thể cho phép bạn tạo thử nghiệm của mình tốt hơn.

Nếu bạn muốn đảm bảo rằng hai nhóm danh sách không có cùng màu hoặc hình dạng ở cùng vị trí với nhóm trước đó, thì bạn có thể kiểm tra điều đó sau khi trộn ngẫu nhiên với cài đặt trước đó.

testing = True 
while testing: 
    newcolors = colors 
    random.shuffle(newcolors) 
    # perform the test that you want to make get testresult True or False 
    if testresult: 
     colors = newcolors 
     testing = False 

Điều này sẽ giữ cho đến khi shuffling testresult trở thành True và loại bỏ tất cả các kết quả không hợp lệ từ random.shuffle()

-1

Trong khi bạn có thể sử dụng kỹ thuật itertools.permutations (Tôi đã thử mà lần đầu tiên), mà sẽ phải mất quá lâu.

Sử dụng này để tạo chuỗi ngẫu nhiên mà không cần các mục mà chia sẻ một tài sản sau đây eachother:

from random import shuffle 

x=["a1","a2","a3","a4","b1","b2","b3","b4","c1","c2","c3","c4","d1","d2","d3","d4"] 

def pairwise(some_list): 
    one = iter(some_list) 
    two = iter(some_list) 
    next(two) 
    for first, second in zip(one, two): 
     yield first, second 

while True: 
    shuffle(x) 
    for first, second in pairwise(x): 
     if first[0] == second[0] or first[1] == second[1]: 
      break 
    else: # nobreak: 
     print(x) 
-1

Bạn có thể xây dựng các mảnh danh sách khôn ngoan bằng cách so sánh một lựa chọn ngẫu nhiên để giá trị cuối cùng.

import random 

options = ["a1", "a2", "a3", "a4", "b1", "b2", "b3", "b4", 
      "c1", "c2", "c3", "c4", "d1", "d2", "d3", "d4"] 

j = random.choice(range(len(options))) 
result = [options.pop(j)] 
last = result[-1] 
while options: 
    j = random.choice(range(len(options))) 
    candidate = options[j] 
    if all([x != y for x, y in zip(last, candidate)]): 
     result.append(options.pop(j)) 
     last = result[-1] 
1

tôi nghi ngờ đây là tốt nhất bằng cách nào, nhưng nó là một cách để làm điều này. Nếu bạn nghĩ về đầu vào của bạn như một ma trận như thế này

a1, b1, c1, d1 
a2, b2, c2, d2 
a3, b3, c3, d3 
a4, b4, c4, d4 

Sau đó, bạn đang mục tiêu trở thành lựa chọn một số ngẫu nhiên ở mỗi lần lặp như vậy mà chỉ số mới không có trong cùng hàng cũng không phải là cùng một cột của ma trận như chỉ mục trước đó và sao cho phần tử mới chưa được chọn trước đó.Đưa rằng vào mã ngây thơ, nó trở nên

import random 
shapes_and_colors=["a1","a2","a3","a4","b1","b2","b3","b4","c1","c2","c3","c4","d1","d2","d3","d4"] 
nRows = 4 
nCols = 4 
inds = [(x,y) for x in range(nRows) for y in range(nCols)] 
def make_random(someArr): 
    toRet = [] 
    n = len(someArr) 
    for i in range(n): 
     possible = [thing for thing in someArr if thing not in toRet] 
     prev = poss = None 
     while poss is None: 
      next_val = random.choice(possible) 
      if next_val == prev: 
       #failed so try again 
       return make_random(someArr) 
      if not toRet or (next_val[0] != toRet[-1][0] and next_val[1] != toRet[-1][1]): 
       poss = next_val 
      prev = next_val 
     toRet += poss, 
    return toRet 



ans= [thing for thing in make_random(shapes_and_colors)] 
print ans 

đầu ra sau một vài Chạy

['c3', 'd4', 'c1', 'd3', 'b1', 'a4', 'b3', 'c4', 'a3', 'b2', 'a1', 'c2', 'd1', 'a2', 'b4', 'd2'] 
['d4', 'b3', 'c1', 'a4', 'b2', 'c4', 'd3', 'a1', 'c3', 'a2', 'b4', 'd2', 'a3', 'b1', 'c2', 'd1'] 

Disclaimer

Do đây là một cách tiếp cận hoàn toàn ngây thơ, đôi khi nó bị mắc kẹt! Giả sử hai chỉ số cuối cùng còn lại là [(2, 2), (3, 2)]. Sau đó, không có cách nào có thể cho các thuật toán để tiến hành mà không vi phạm các hạn chế. Ngay bây giờ, tôi đang xử lý nó với một cuộc gọi đệ quy, đó không phải là lý tưởng.