kết hợp giữa hai danh sách?


184

Đã được một thời gian và tôi gặp khó khăn trong việc xoay quanh một thuật toán mà tôi đang cố gắng thực hiện. Về cơ bản, tôi có hai danh sách và muốn nhận tất cả các kết hợp của hai danh sách.

Tôi có thể không giải thích nó chính xác vì vậy đây là một ví dụ.

name = 'a', 'b'
number = 1, 2

đầu ra trong trường hợp này sẽ là:

1.  A1 B2
2.  B1 A2

Phần khó khăn là tôi có thể có nhiều vật phẩm hơn trong biến số tên của tên lửa so với các vật phẩm trong biến số Số tên của con số (số sẽ luôn bằng hoặc ít hơn biến số tên).

Tôi bối rối làm thế nào để thực hiện tất cả các kết hợp (lồng nhau cho vòng lặp?) Và thậm chí còn bối rối hơn về logic để thay đổi các mục trong biến tên trong trường hợp có nhiều mục trong tên hơn trong danh sách số.

Tôi không phải là lập trình viên giỏi nhất nhưng tôi nghĩ tôi có thể thử nếu ai đó có thể giúp tôi làm rõ logic / algoriy nhịp để đạt được điều này. Vì vậy, tôi vừa bị mắc kẹt trên các vòng lặp lồng nhau.

Cập nhật:

Đây là đầu ra với 3 biến và 2 số:

name = 'a', 'b', 'c'
number = 1, 2

đầu ra:

1.  A1 B2
2.  B1 A2
3.  A1 C2
4.  C1 A2
5.  B1 C2
6.  C1 B2


1
@ dm03514 Tôi đã thấy điều đó và đã tìm thấy các ví dụ cho các mục tiêu hơi giống nhau khi sử dụng itertools nhưng tôi đang tạo mẫu bằng python nhưng sẽ viết mã cuối cùng bằng ngôn ngữ khác vì vậy tôi không muốn sử dụng bất kỳ công cụ nào không có sẵn.
dùng1735075

1
Những gì bạn đang yêu cầu không thực sự có ý nghĩa. Nếu danh sách đầu tiên chứa A, B, C và danh sách thứ hai chứa 1,2, bạn sẽ mong đợi kết quả gì? Có thể được thực hiện nếu ví dụ bạn đưa ra có 4 kết quả khác nhau của một chữ cái và một số mỗi chữ cái (A1, A2, B1, B2) hoặc nếu cả hai danh sách phải có cùng kích thước.
interjay

1
Tôi đồng ý với interjay. Vui lòng chỉ định kết quả trong trường hợp kích thước không bằng nhau, nếu không, không thể cung cấp giải pháp chung.
Bakuriu

Xin chào mọi người, tôi đã cập nhật câu trả lời để hiển thị đầu ra với 3 tên và 2 số..Tôi nghĩ rằng tôi đã giải thích nó tốt, không chắc tại sao downvote.
dùng1735075

Câu trả lời:


93

Lưu ý : Câu trả lời này dành cho câu hỏi cụ thể được hỏi ở trên. Nếu bạn ở đây từ Google và chỉ tìm cách để có được một sản phẩm của Cartesian bằng Python, itertools.producthoặc một sự hiểu biết danh sách đơn giản có thể là những gì bạn đang tìm kiếm - hãy xem các câu trả lời khác.


Giả sử len(list1) >= len(list2). Sau đó, những gì bạn dường như muốn là lấy tất cả các hoán vị độ dài len(list2)từ list1và khớp chúng với các mục từ list2. Trong trăn:

import itertools
list1=['a','b','c']
list2=[1,2]

[list(zip(x,list2)) for x in itertools.permutations(list1,len(list2))]

Trả về

[[('a', 1), ('b', 2)], [('a', 1), ('c', 2)], [('b', 1), ('a', 2)], [('b', 1), ('c', 2)], [('c', 1), ('a', 2)], [('c', 1), ('b', 2)]]

1
Kết quả là chính xác những gì tôi muốn, nhưng có thể chia sẻ logic đằng sau làm thế nào để làm điều đó? Nếu tôi chuyển đổi mã của mình sang C hoặc Java, tôi sẽ không có quyền truy cập vào zip hoặc itertools (mặc dù chúng giúp cuộc sống rất dễ dàng)
user1735075

3
@ user1735075 Hãy xem tài liệu
lười

1
@ user1735075: bạn có biết python là nguồn mở không? Vì vậy, bạn có thể chỉ cần tải về các nguồn và xem những gì họ làm. +1 cho ông Steak vì đã chỉ ra rằng tài liệu thực sự có một triển khai mẫu không sử dụng zipvà tương tự.
Bakuriu

2
tôi thực sự không thể làm điều này hoạt động, ngay cả với ví dụ của bạn ... tất cả những gì tôi nhận được là một danh sách các đối tượng zip ..: |
m1nkeh

1
@logic cung cấp những gì nên là giải pháp được chấp nhận.
Bernhard Wagner

497

Cách đơn giản nhất là sử dụng itertools.product:

a = ["foo", "melon"]
b = [True, False]
c = list(itertools.product(a, b))
>> [("foo", True), ("foo", False), ("melon", True), ("melon", False)]

10
OP đã không yêu cầu một sản phẩm của Cartesian và câu trả lời này (cũng như hầu hết các sản phẩm khác) không đưa ra kết quả mong đợi được chỉ định trong câu hỏi.
interjay

17
@interjay bạn nói rất đúng nhưng vì quá nhiều người dường như thấy câu trả lời này là chính xác nên tôi chỉ có thể cho rằng tiêu đề của câu hỏi là thiếu ngữ cảnh.
xpy

3
@xpy Tiêu đề quá ngắn để giải thích mọi thứ. Đó là lý do tại sao bạn cần đọc câu hỏi thực tế.
interjay

10
OP muốn hoán vị, nhưng Google gửi bất kỳ ai đang tìm kiếm sự kết hợp (như tôi) cho câu trả lời này - rất vui khi thấy nó nhận được 8 lần số phiếu!
Josh Friedlander

158

Có thể đơn giản hơn cách đơn giản nhất ở trên:

>>> a = ["foo", "bar"]
>>> b = [1, 2, 3]
>>> [(x,y) for x in a for y in b]  # for a list
[('foo', 1), ('foo', 2), ('foo', 3), ('bar', 1), ('bar', 2), ('bar', 3)]
>>> ((x,y) for x in a for y in b)  # for a generator if you worry about memory or time complexity.
<generator object <genexpr> at 0x1048de850>

không có bất kỳ nhập khẩu


Giải pháp tốt nhất! Cảm ơn bạn! Các giải pháp khác đều sai hoặc chỉ hoạt động trong các trường hợp cụ thể như a> b, v.v.
Philipp Schwarz

3
Giải pháp Pythonic nhất! (và tránh nhập khẩu không cần thiết)
Dalker

6
Độ phức tạp thời gian là O (n ^ 2)
Deepak Sharma

2
Đặt cược giải pháp !! Những điều cơ bản trần trụi là cách tốt nhất luôn luôn
Sabyasachi 23/2/19

22

Tôi đã tìm kiếm một danh sách nhân với chỉ các kết hợp duy nhất, được cung cấp dưới dạng chức năng này.

import itertools
itertools.combinations(list, n_times)

Đây là một đoạn trích từ các tài liệu Python trên itertools Điều đó có thể giúp bạn tìm thấy những gì bạn đang tìm kiếm.

Combinatoric generators:

Iterator                                 | Results
-----------------------------------------+----------------------------------------
product(p, q, ... [repeat=1])            | cartesian product, equivalent to a 
                                         |   nested for-loop
-----------------------------------------+----------------------------------------
permutations(p[, r])                     | r-length tuples, all possible 
                                         |   orderings, no repeated elements
-----------------------------------------+----------------------------------------
combinations(p, r)                       | r-length tuples, in sorted order, no 
                                         |   repeated elements
-----------------------------------------+----------------------------------------
combinations_with_replacement(p, r)      | r-length tuples, in sorted order, 
                                         | with repeated elements
-----------------------------------------+----------------------------------------
product('ABCD', repeat=2)                | AA AB AC AD BA BB BC BD CA CB CC CD DA DB DC DD
permutations('ABCD', 2)                  | AB AC AD BA BC BD CA CB CD DA DB DC
combinations('ABCD', 2)                  | AB AC AD BC BD CD
combinations_with_replacement('ABCD', 2) | AA AB AC AD BB BC BD CC CD DD

11

Bạn có thể muốn thử hiểu một danh sách một dòng:

>>> [name+number for name in 'ab' for number in '12']
['a1', 'a2', 'b1', 'b2']
>>> [name+number for name in 'abc' for number in '12']
['a1', 'a2', 'b1', 'b2', 'c1', 'c2']

10

cách tốt nhất để tìm ra tất cả các kết hợp cho số lượng lớn danh sách là:

import itertools
from pprint import pprint

inputdata = [
    ['a', 'b', 'c'],
    ['d'],
    ['e', 'f'],
]
result = list(itertools.product(*inputdata))
pprint(result)

kết quả sẽ là:

[('a', 'd', 'e'),
 ('a', 'd', 'f'),
 ('b', 'd', 'e'),
 ('b', 'd', 'f'),
 ('c', 'd', 'e'),
 ('c', 'd', 'f')]

Cảm ơn, câu trả lời tuyệt vời!
toinbis

10

Hoặc câu trả lời KISS cho danh sách ngắn:

[(i, j) for i in list1 for j in list2]

Không phải là trình diễn như itertools nhưng bạn đang sử dụng python nên hiệu suất không phải là mối quan tâm hàng đầu của bạn ...

Tôi thích tất cả các câu trả lời khác quá!


8

một cải tiến nhỏ cho câu trả lời từ interjay, để đưa ra kết quả dưới dạng danh sách làm phẳng.

>>> list3 = [zip(x,list2) for x in itertools.permutations(list1,len(list2))]
>>> import itertools
>>> chain = itertools.chain(*list3)
>>> list4 = list(chain)
[('a', 1), ('b', 2), ('a', 1), ('c', 2), ('b', 1), ('a', 2), ('b', 1), ('c', 2), ('c', 1), ('a', 2), ('c', 1), ('b', 2)]

tham khảo từ liên kết này



4

Trả lời câu hỏi "đưa ra hai danh sách, tìm tất cả các hoán vị có thể có của các cặp của một mục từ mỗi danh sách" và sử dụng chức năng Python cơ bản (nghĩa là không có itertools) và do đó, dễ dàng sao chép cho các ngôn ngữ lập trình khác:

def rec(a, b, ll, size):
    ret = []
    for i,e in enumerate(a):
        for j,f in enumerate(b):
            l = [e+f]
            new_l = rec(a[i+1:], b[:j]+b[j+1:], ll, size)
            if not new_l:
                ret.append(l)
            for k in new_l:
                l_k = l + k
                ret.append(l_k)
                if len(l_k) == size:
                    ll.append(l_k)
    return ret

a = ['a','b','c']
b = ['1','2']
ll = []
rec(a,b,ll, min(len(a),len(b)))
print(ll)

Trả về

[['a1', 'b2'], ['a1', 'c2'], ['a2', 'b1'], ['a2', 'c1'], ['b1', 'c2'], ['b2', 'c1']]

2

Các câu trả lời tốt hơn cho điều này chỉ hoạt động cho độ dài cụ thể của danh sách được cung cấp.

Đây là một phiên bản hoạt động cho bất kỳ độ dài đầu vào. Nó cũng làm cho thuật toán rõ ràng về các khái niệm toán học của sự kết hợp và hoán vị.

from itertools import combinations, permutations
list1 = ['1', '2']
list2 = ['A', 'B', 'C']

num_elements = min(len(list1), len(list2))
list1_combs = list(combinations(list1, num_elements))
list2_perms = list(permutations(list2, num_elements))
result = [
  tuple(zip(perm, comb))
  for comb in list1_combs
  for perm in list2_perms
]

for idx, ((l11, l12), (l21, l22)) in enumerate(result):
  print(f'{idx}: {l11}{l12} {l21}{l22}')

Kết quả này:

0: A1 B2
1: A1 C2
2: B1 A2
3: B1 C2
4: C1 A2
5: C1 B2
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.