2011-02-05 33 views
5

Tôi có hai bộ lựa chọn:kiểm tra tất cả các kết hợp trong Python

optionList1 = [a1,a2,a3,...,an] 
optionList2 = [b1,b2,b3,...,bn] 

Số lượng các yếu tố trong optionlists không nhất thiết phải bằng nhau và tôi phải chọn từ optionlist đầu tiên hai lần. Làm thế nào để đảm bảo rằng tôi đã thử mọi kết hợp của 2 tùy chọn từ danh sách đầu tiên và một từ danh sách thứ hai. Một lựa chọn ví dụ được đặt bên dưới ...

selectedOptions = [an1,an2,bn] 
+1

xin lỗi, nhưng tôi không hiểu rõ những gì bạn đang cố gắng làm. Bạn có cần một bảng của tất cả các kết hợp có thể có của các yếu tố các yếu tố, mà không ai là từ cùng một danh sách? Nên bất kỳ nút nào không bao giờ là Không? – fncomp

+0

Tôi đoán tôi đã chậm để tìm ra những gì bạn muốn. – fncomp

Trả lời

6

Giả sử bạn không muốn các mục trùng lặp khỏi list1, đây là một máy phát điện mà bạn có thể sử dụng để lặp qua tất cả các kết hợp:

def combinations(list1, list2): 
    return ([opt1, opt2, opt3] 
      for i,opt1 in enumerate(list1) 
      for opt2 in list1[i+1:] 
      for opt3 in list2) 

này, tuy nhiên, không chọn các tùy chọn tương tự từ list1 theo thứ tự khác nhau. Nếu bạn muốn để có được cả hai [a1, a2, b1] và [a2, a1, b1] sau đó bạn có thể sử dụng:

def combinations(list1, list2): 
    return ([opt1, opt2, opt3] 
      for opt1 in list1 
      for opt2 in list1 
      for opt3 in list2 if opt1 != opt2) 
+2

Trong thuật ngữ python, một máy phát điện là cái gì đó sử dụng 'yield'. Điều này có bất lợi của việc lưu trữ toàn bộ danh sách với các tùy chọn trong bộ nhớ. –

+1

Và tất nhiên OP có thể gọi điều này với hai thông số đầu tiên là cùng một danh sách. kết hợp (optionList1, optionList1, optionList2) chỉ trong trường hợp không rõ ràng. – Spacedman

+1

Hàm thực sự trả về biểu thức trình tạo, do đó nó không xây dựng toàn bộ danh sách trong bộ nhớ. – shang

2

Một cách cần làm là sử dụng itertools.product.

for x, y, z in itertools.product(optionlist1,optionlist1,optionlist2): 
    print x,y,z 
+0

Điều này không thử tất cả các kết hợp. Thay vào đó nó khớp với các chỉ mục trong danh sách, chỉ trả lại (a1, a1, b1), (a2, a2, b2) .... (an, a, bn) nếu cả hai đều có cùng độ dài. –

+0

@Peter.Có, tôi chỉ cập nhật nó với câu trả lời đúng. Tôi thấy bạn đã chỉ ra câu trả lời đúng. –

+0

Bạn không cần phải nối thêm danh sách với các giá trị rỗng. itertools.product() có thể xử lý danh sách (hoặc vòng lặp) với độ dài khác nhau. –

6

Bạn có thể sử dụng itertools.product cho việc này. Nó trả về tất cả các kết hợp có thể.

Ví dụ

for a1, a2, b in itertools.product(optionlist1,optionlist1,optionlist2): 
    do_something(a1,a2,b) 

này sẽ tạo ra "đôi" như [a1, a1, b2] và [a2, a3, b2], [a3, a2, b2]. Bạn có thể sửa lỗi này bằng bộ lọc. Các trường hợp sau ngăn chặn mọi đôi *:

for a1,a2,b in itertools.ifilter(lambda x: x[0]<x[1], itertools.product(optionlist1,optionlist1,optionlist2)): 
    do_something(a1,a2,b) 

(*) Điều này giả định rằng các tùy chọn có một số trường hợp tự nhiên.

shang 's answer cũng rất tốt. Tôi đã viết một số mã để so sánh chúng:

from itertools import ifilter, product 
import random 
from timeit import repeat 

def generator_way(list1, list2): 
    def combinations(list1, list2): 
     return ([opt1, opt2, opt3] 
       for i,opt1 in enumerate(list1) 
       for opt2 in list1[i+1:] 
       for opt3 in list2) 
    count = 0 
    for a1,a2,b in combinations(list1,list2): 
     count += 1 

    return count 

def itertools_way(list1,list2): 
    count = 0 
    for a1,a2,b in ifilter(lambda x: x[0] < x[1], product(list1,list1,list2)): 
     count += 1 
    return count 

list1 = range(0,100) 
random.shuffle(list1) 
list2 = range(0,100) 
random.shuffle(list2) 

print sum(repeat(lambda: generator_way(list1,list2),repeat = 10, number=1))/10 
print sum(repeat(lambda: itertools_way(list1,list2),repeat = 10, number=1))/10 

Và kết quả là:

0.189330005646 
0.428138256073 

Vì vậy, các phương pháp phát nhanh. Tuy nhiên, tốc độ không phải là tất cả. Cá nhân tôi tìm thấy mã của tôi 'sạch hơn', nhưng sự lựa chọn là của bạn!

(Btw, họ cung cấp cho cả hai tội giống hệt nhau, vì vậy cả hai đều như nhau đúng.)

3

Nghe có vẻ với tôi như bạn đang tìm kiếm itertools.product()

>>> options_a = [1,2] 
>>> options_b = ['a','b','c'] 
>>> list(itertools.product(options_a, options_a, options_b)) 
[(1, 1, 'a'), 
(1, 1, 'b'), 
(1, 1, 'c'), 
(1, 2, 'a'), 
(1, 2, 'b'), 
(1, 2, 'c'), 
(2, 1, 'a'), 
(2, 1, 'b'), 
(2, 1, 'c'), 
(2, 2, 'a'), 
(2, 2, 'b'), 
(2, 2, 'c')] 
+0

Tôi không chắc tôi hiểu: theo như tôi có thể biết, cách này hoạt động theo cùng một cách bất kể độ dài của một trong hai danh sách. Về việc liệu nó có trả lời câu hỏi hay không, rất khó để nói, vì bản thân câu hỏi có phần mơ hồ: OP không xác định xem các nhóm lựa chọn tùy chọn có các mục trùng lặp từ tập hợp các tùy chọn đầu tiên sẽ được đưa vào hay không. Bởi vì sự mơ hồ này tôi không thể khẳng định rằng đây chính xác là giải pháp cho vấn đề của OP, nhưng để nói nó "thậm chí không đến gần" có vẻ khá khắc nghiệt. –

6

Kết hợp productpermutations từ itertools giả sử bạn không muốn trùng lặp từ danh sách đầu tiên:

>>> from itertools import product,permutations 
>>> o1 = 'a1 a2 a3'.split() 
>>> o2 = 'b1 b2 b3'.split() 
>>> for (a,b),c in product(permutations(o1,2),o2): 
...  print a,b,c 
... 
a1 a2 b1 
a1 a2 b2 
a1 a2 b3 
a1 a3 b1 
a1 a3 b2 
a1 a3 b3 
a2 a1 b1 
a2 a1 b2 
a2 a1 b3 
a2 a3 b1 
a2 a3 b2 
a2 a3 b3 
a3 a1 b1 
a3 a1 b2 
a3 a1 b3 
a3 a2 b1 
a3 a2 b2 
a3 a2 b3 
+0

Giải pháp tuyệt vời !! –

+1

Rất đẹp! Cũng lưu ý rằng bạn có thể thay thế 'hoán vị' bằng' kết hợp' nếu bạn không muốn lặp lại các cặp với thứ tự khác nhau. – shang

+0

@shang, tôi đã có mà ban đầu nhưng nó không rõ ràng những gì OP muốn. Tôi nghĩ hoán vị có nhiều khả năng hơn. OP có thể được OK với các bản sao, quá, sau đó 'sản phẩm (o1, o1, o2)' sẽ là tốt. –

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