Tạo hoán vị có lặp lại


84

Tôi biết về itertools, nhưng có vẻ như nó chỉ có thể tạo ra các hoán vị mà không lặp lại.

Ví dụ: tôi muốn tạo tất cả các cuộn xúc xắc có thể có cho 2 viên xúc xắc. Vì vậy, tôi cần tất cả các hoán vị có kích thước 2 của [1, 2, 3, 4, 5, 6] bao gồm các lần lặp lại: (1, 1), (1, 2), (2, 1) ... vv

Nếu có thể, tôi không muốn thực hiện điều này từ đầu

Câu trả lời:


144

Bạn đang tìm kiếm Sản phẩm Descartes .

Trong toán học, tích Descartes (hay tập hợp sản phẩm) là tích trực tiếp của hai tập hợp.

Trong trường hợp của bạn, đây sẽ là {1, 2, 3, 4, 5, 6}x {1, 2, 3, 4, 5, 6}. itertoolscó thể giúp bạn ở đó:

import itertools
x = [1, 2, 3, 4, 5, 6]
[p for p in itertools.product(x, repeat=2)]
[(1, 1), (1, 2), (1, 3), (1, 4), (1, 5), (1, 6), (2, 1), (2, 2), (2, 3), 
 (2, 4), (2, 5), (2, 6), (3, 1), (3, 2), (3, 3), (3, 4), (3, 5), (3, 6), 
 (4, 1), (4, 2), (4, 3), (4, 4), (4, 5), (4, 6), (5, 1), (5, 2), (5, 3), 
 (5, 4), (5, 5), (5, 6), (6, 1), (6, 2), (6, 3), (6, 4), (6, 5), (6, 6)]

Để nhận được một cuộn xúc xắc ngẫu nhiên (theo một cách hoàn toàn không hiệu quả ):

import random
random.choice([p for p in itertools.product(x, repeat=2)])
(6, 3)

8
Đây là một cách cực kỳ kém hiệu quả để nhận được 2 cuộn xúc xắc… Hai cuộc gọi đến random.randintsẽ đơn giản và hiệu quả hơn.
Eric O Lebigot

Random xúc xắc cuộn sẽ nhanh hơn nhiều khi bạn không tạo ra tất cả các cặp có thể: [random.randint (1,6) for i in xrange (2)]
liori

13
Tôi không thực sự cố gắng tạo các cuộn ngẫu nhiên, chỉ để liệt kê tất cả các cuộn có thể có.
Bwmat


7

Trong python 2.7 và 3.1 có một itertools.combinations_with_replacementchức năng:

>>> list(itertools.combinations_with_replacement([1, 2, 3, 4, 5, 6], 2))
[(1, 1), (1, 2), (1, 3), (1, 4), (1, 5), (1, 6), (2, 2), (2, 3), (2, 4), 
 (2, 5), (2, 6), (3, 3), (3, 4), (3, 5), (3, 6), (4, 4), (4, 5), (4, 6),
 (5, 5), (5, 6), (6, 6)]

12
Giải pháp này thua trên sự kết hợp (2, 1), (3, 2), (3, 1)và tương tự ... Nói chung nó lá ra tất cả các kết hợp mà cuộn thứ hai là thấp hơn so với lần đầu tiên.
holroy

1

Trong trường hợp này, việc hiểu danh sách là không đặc biệt cần thiết.

Được

import itertools as it


seq = range(1, 7)
r = 2

list(it.product(seq, repeat=r))

Chi tiết

Rõ ràng, tích Descartes có thể tạo ra các tập con các hoán vị. Tuy nhiên, nó theo sau rằng:

  • với sự thay thế: tạo ra tất cả các hoán vị n r quaproduct
  • không cần thay thế: bộ lọc từ cái sau

Hoán vị có thay thế, n r

[x for x in it.product(seq, repeat=r)]

Hoán vị không thay thế, n!

[x for x in it.product(seq, repeat=r) if len(set(x)) == r]
# Equivalent
list(it.permutations(seq, r))  

Do đó, tất cả các hàm tổ hợp có thể được thực hiện từ product:


-1

Tôi nghĩ rằng tôi đã tìm thấy một giải pháp chỉ sử dụng lambdas, mapreduce.

product_function = lambda n: reduce(lambda x, y: x+y, map(lambda i: list(map(lambda j: (i, j), np.arange(n))), np.arange(n)), [])

Về cơ bản, tôi đang ánh xạ một hàm lambda đầu tiên cho một hàng, lặp lại các cột

list(map(lambda j: (i, j), np.arange(n)))

thì nó được sử dụng làm đầu ra của một hàm lambda mới

lambda i:list(map(lambda j: (i, j), np.arange(n)))

được ánh xạ trên tất cả các hàng có thể có

map(lambda i: list(map(lambda j: (i, j), np.arange(n))), np.arange(m))

và sau đó chúng tôi giảm tất cả các danh sách kết quả thành một.

thậm chí còn tốt hơn

Cũng có thể sử dụng hai số khác nhau.

prod= lambda n, m: reduce(lambda x, y: x+y, map(lambda i: list(map(lambda j: (i, j), np.arange(m))), np.arange(n)), [])

-2

Trước tiên, bạn sẽ muốn biến trình tạo được trả về bởi itertools.permutations (danh sách) thành một danh sách trước. Sau đó, thứ hai, bạn có thể sử dụng set () để xóa các bản sao giống như bên dưới:

def permutate(a_list):
    import itertools
    return set(list(itertools.permutations(a_list)))

1
Điều đó không bao gồm các bản sao.
Björn Lindqvist

1
OP muốn một cách rõ ràng bản sao
Levi Lesches
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.