Stelios M
Stelios M

Reputation: 160

Combination between lists ignoring elements within and list and ignoring ordering of pairs

I have two lists:

list1=['a', 'z', 'd', 'e','b']
list2=['d','e', 'b' ]

and I need the combinations (not permutations) of the elements of these two lists. I have tried itertools.combinations and itertools.product, but I am not getting exactly what I want. For example, ('d','d') would be wrong. ('a','z') would also be wrong because 'a' and 'z' belong to the same list (list1) and neither one of them appears in list2. Finally, I do not want both ('d','e') and ('e','d') - only one of these pairs, since order does not matter. The ideal output would be:

('a','d'), ('a','e'), ('a','b'),
('z','d'), ('z','e'), ('z','b'),
('d','e'), ('d','b'), ('e','b')

Edit: generally, list2 will not always be a subset of list1, but I want to handle that case as well. There could also be an overlap of these two lists and not a full subset.

Upvotes: 3

Views: 1053

Answers (5)

AGN Gazer
AGN Gazer

Reputation: 8378

from itertools import chain, product, combinations
common = set(list1) & set(list2)
sdiff = set(list1) ^ set(list2)
result = [i for i in chain(product(common, sdiff), combinations(common, 2))]

Then,

>>> print(a)
[('b', 'a'), ('b', 'z'), ('e', 'a'), ('e', 'z'), ('d', 'a'), ('d', 'z'), ('b', 'e'), ('b', 'd'), ('e', 'd')]

Upvotes: 1

FMc
FMc

Reputation: 42411

You can deal with examples like ('d', 'e') and ('e', 'd') by sorting the inner tuples:

from itertools import product

xs = ['a', 'z', 'd', 'e', 'b']
ys = ['d', 'e', 'b']

got = set(tuple(sorted(t)) for t in product(xs, ys) if t[0] != t[1])

Upvotes: 1

Kevin DS.
Kevin DS.

Reputation: 131

Nonefficient way, but working :

print(set([z for x in list1 for z in [tuple(x+y) if ord(x) < ord(y) else tuple(y+x) for y in list2 if x != y]]))

{('a', 'e'), ('e', 'z'), ('b', 'z'), ('d', 'e'), ('a', 'b'), ('b', 'd'), ('b', 'e'), ('d', 'z'), ('a', 'd')}

I realy prefer @jpp solution !

Upvotes: 0

jpp
jpp

Reputation: 164673

Since order does not matter, you should use set or frozenset for order-agnostic collections.

One brute-force solution is to utilise itertools.product, but use set combined with a list comprehension to remove duplicates:

from itertools import product

list1=['a', 'z', 'd', 'e','b']
list2=['d','e', 'b' ]

res = [i for i in set(map(frozenset, product(list1, list2))) if len(i) > 1]

print(res)

[frozenset({'b', 'e'}),
 frozenset({'a', 'e'}),
 frozenset({'d', 'z'}),
 frozenset({'b', 'd'}),
 frozenset({'a', 'd'}),
 frozenset({'d', 'e'}),
 frozenset({'b', 'z'}),
 frozenset({'a', 'b'}),
 frozenset({'e', 'z'})]

Upvotes: 2

niraj
niraj

Reputation: 18208

May be not most efficient but you can try following:

list1=['a', 'z', 'd', 'e','b']
list2=['d','e', 'b' ]

result = []
for i in list1:
    for j in list2:
        if i != j and (j,i) not in result:
            result.append((i,j))
print(result)

Result:

[('a', 'd'), ('a', 'e'), ('a', 'b'), 
 ('z', 'd'), ('z', 'e'), ('z', 'b'), 
 ('d', 'e'), ('d', 'b'), ('e', 'b')]

Upvotes: 2

Related Questions