2つのリスト間の組み合わせ?


187

久しぶりに、自分が作ろうとしているアルゴリズムに頭を悩ませるのに苦労しています。基本的に、2つのリストがあり、2つのリストのすべての組み合わせを取得したいと考えています。

私はそれを正しく説明していないかもしれないので、ここに例があります。

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

この場合の出力は次のようになります。

1.  A1 B2
2.  B1 A2

トリッキーな部分は、「name」変数の項目が「number」変数の項目よりも多い場合があることです(番号は常にname変数以下になります)。

すべての組み合わせ(ネストされたforループ?)を実行する方法に混乱があります。また、番号リストにある項目よりも名前に項目が多い場合に、name変数の項目をシフトするロジックがさらに混乱しています。

私は最高のプログラマーではありませんが、誰かがロジック/アルゴリズムを明確にしてこれを達成するのを手伝ってくれるなら、私はそれを試してみることができると思います。だから私はネストされたforループで立ち往生しているところです。

更新:

これは、3つの変数と2つの数値の出力です。

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

出力:

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


1
@ dm03514私はそれを見ました、そしてitertoolsを使用していくらか類似した目標の例を見つけましたが、私はpythonでプロトタイピングしていますが、最終的なコードを別の言語で書くので、他の方法で利用できないツールを使いたくありません。
user1735075 2012年

1
あなたが求めていることは本当に意味がありません。最初のリストにA、B、Cが含まれ、2番目のリストに1、2が含まれている場合、どのような結果が予想されますか?あなたが与えた例が1つの文字と1つの数字(A1、A2、B1、B2)の4つの異なる結果を持っている場合、または両方のリストが同じサイズでなければならない場合に実行できます。
interjay 2012年

1
私はインタージェイに同意します。サイズが等しくない場合に結果を指定してください。そうでない場合、一般的な解決策を提供することはできません。
12

こんにちは皆さん、私は3つの名前と2つの数字で出力を表示するように回答を更新しました。理由はよくわかりませんでした。
user1735075 2012年

回答:


93

:この回答は、上記の特定の質問に対するものです。あなたがGoogleからここにいて、Pythonでデカルト積を取得する方法を探しているitertools.product場合、または単純なリスト内包が探しているものである可能性があります。他の回答を参照してください。


と仮定しlen(list1) >= len(list2)ます。そして、どのようなあなたが望むように見えることは長さのすべての順列を取ることですlen(list2)からlist1とlist2のからアイテムでそれらを一致させます。Pythonでは:

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

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

戻り値

[[('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
結果はまさに私が望むものですが、それを行う方法の背後にあるロジックを共有することは可能ですか?私のコードをCまたはJavaに変換すると、zipまたはitertoolsにアクセスできなくなります(ただし、これらを使用すると非常に簡単になります)
user1735075

3
@ user1735075見て持っているドキュメント
ナマケモノ

1
@ user1735075:Pythonがオープンソースであることを知っていますか?したがって、単にソースをダウンロードして、それらが何をするかを見ることができます。ドキュメントに実際には使用されていないzip類似のサンプル実装があることを指摘してくれたSteak氏への+1 。
12

2
あなたの例でさえ、私は文字通りこれを機能させることができません...私が得るすべてはzipオブジェクトのリストです..:|
m1nkeh

1
@logicは、受け入れられるソリューションを提供します。
Bernhard Wagner

502

最も簡単な方法は次のようにすることitertools.productです:

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

11
OPはデカルト積を求めていませんでした。この回答(および他のほとんどの回答)は、質問で指定された期待される結果を提供しません。
インタージェイ2017

17
@interjayあなたは正しいですが、あまりに多くの人々がこの答えを正しいと思うように思われるので、質問のタイトルにコンテキストが欠けているとしか思えません。
xpy 2017

3
@xpyタイトルはすべてを説明するには短すぎます。そのため、実際の質問を読む必要があります。
インタージェイ2017

10
OPは順列を望んでいたが、Googleは組み合わせを探している人(私のような)をこの答えに送りました。投票が8倍になったのを見てうれしいです!
Josh Friedlander

160

上記の最も単純なものよりも単純な場合があります。

>>> 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>

インポートなし


最高のソリューション!ありがとうございました!その他のソリューションは> Bなどのような特定の例のいずれかで、プレーン間違っていたり、唯一の仕事です
フィリップ・シュワルツ

3
ほとんどのPythonicソリューション!(不要なインポートを回避します)
Dalker

6
時間の複雑さはO(n ^ 2)
Deepak Sharma

2
ベットソリューション!! ベアベーシックは常に最善の方法です
Sabyasachi

22

この関数として提供されている、一意の組み合わせのみで乗算されたリストを探していました。

import itertools
itertools.combinations(list, n_times)

ここでは、Pythonのドキュメントitertoolsから抜粋として、それがあなたが探しているものを見つけるのに役立つかもしれません。

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

あなたは一行のリストの理解を試してみたいかもしれません:

>>> [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']

11

多数のリストのすべての組み合わせを見つける最良の方法は次のとおりです。

import itertools
from pprint import pprint

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

結果は次のようになります。

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

ありがとう、素晴らしい答えです!
-toinbis

10

または短いリストのKISS回答:

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

itertoolsほどパフォーマンスは高くありませんが、Pythonを使用しているため、パフォーマンスはすでに最大の関心事ではありません...

私は他のすべての答えも好きです!


8

結果をフラットなリストにするために、interjayからの回答を少し改善しました。

>>> 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)]

このリンクからの参照



4

「2つのリストがある場合、各リストから1つのアイテムのペアのすべての可能な順列を見つける」という質問に答え、基本的なPython機能を使用して(つまり、itertoolsを使用しない)、他のプログラミング言語で簡単に複製できるようにします。

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)

戻り値

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

2

これに対するより良い答えは、提供されているリストの特定の長さに対してのみ機能します。

以下は、任意の長さの入力で機能するバージョンです。また、組み合わせと順列の数学的概念の観点からアルゴリズムを明確にします。

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}')

これは出力します:

0: A1 B2
1: A1 C2
2: B1 A2
3: B1 C2
4: C1 A2
5: C1 B2
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.