Remove particular combinations from itertools.combinations - python

Suppose we have a pair of tuples where tuples can be of different length. Let's call them tuples t1 and t2:
t1 = ('A', 'B', 'C')
t2 = ('d', 'e')
Now I compute all combinations of length 2 from both tuples using itertools:
import itertools
tuple(itertools.combinations(t1 + t2, 2))
Itertools generator produces all possible combinations, but I need only those which occurs between tuples; the expected output is
(('A', 'd'), ('A', 'e'), ('B', 'd'), ('B', 'e'), ('C', 'd'), ('C', 'e'))
I wonder what is best approach to remove undesired combination.

You need itertools.product :
>>> t1 = ('A', 'B', 'C')
>>> t2 = ('d', 'e')
>>> from itertools import product
>>>
>>> list(product(t1,t2))
[('A', 'd'), ('A', 'e'), ('B', 'd'), ('B', 'e'), ('C', 'd'), ('C', 'e')]
If you are dealing with short tuples you can simply do this job with a list comprehension :
>>> [(i,j) for i in t1 for j in t2]
[('A', 'd'), ('A', 'e'), ('B', 'd'), ('B', 'e'), ('C', 'd'), ('C', 'e')]

Related

how can I fix this Towers of Hanoi program for my desired output?

def moveTower(height,fromPole, toPole, withPole):
if height >= 1:
moveTower(height-1,fromPole,withPole,toPole)
moveDisk(fromPole,toPole)
moveTower(height-1,withPole,toPole,fromPole)
def moveDisk(fp,tp):
print("("+fp + "," +tp+')')
moveTower(4,"A","B","C")
I need the output to be a list of tuples (ex: [('A','C'),('A','B'), ...])
Current output:
(A,C)
(A,B)
(C,B)
(A,C)
(B,A)
(B,C)
(A,C)
(A,B)
(C,B)
(C,A)
(B,A)
(C,B)
(A,C)
(A,B)
(C,B)
You should not print the elements. Probably the most elegant is here to construct a generator:
def moveTower(height,fromPole, toPole, withPole):
if height >= 1:
yield from moveTower(height-1,fromPole,withPole,toPole)
yield (fromPole, toPole)
yield from moveTower(height-1,withPole,toPole,fromPole)
yield <expr> here thus emits the value that is constructed by the <expr> in a generator, and yield from <iterable> is used to emit all elements from the <iterable> as elements of this generator.
We can then use list(..) to materialize the generator:
>>> list(moveTower(2, *'ABC'))
[('A', 'C'), ('A', 'B'), ('C', 'B')]
>>> list(moveTower(3, *'ABC'))
[('A', 'B'), ('A', 'C'), ('B', 'C'), ('A', 'B'), ('C', 'A'), ('C', 'B'), ('A', 'B')]
>>> list(moveTower(4, *'ABC'))
[('A', 'C'), ('A', 'B'), ('C', 'B'), ('A', 'C'), ('B', 'A'), ('B', 'C'), ('A', 'C'), ('A', 'B'), ('C', 'B'), ('C', 'A'), ('B', 'A'), ('C', 'B'), ('A', 'C'), ('A', 'B'), ('C', 'B')]
The simplest modification to your code would be to append them to a list:
result = []
def moveTower(height,fromPole, toPole, withPole):
if height >= 1:
moveTower(height-1,fromPole,withPole,toPole)
moveDisk(fromPole,toPole)
moveTower(height-1,withPole,toPole,fromPole)
def moveDisk(fp,tp):
result.append((fp,tp))
moveTower(4,"A","B","C")
print(result)
Output:
[('A', 'C'), ('A', 'B'), ('C', 'B'), ('A', 'C'), ('B', 'A'), ('B', 'C'), ('A', 'C'), ('A', 'B'), ('C', 'B'), ('C', 'A'), ('B', 'A'), ('C', 'B'), ('A', 'C'), ('A', 'B'), ('C', 'B')]

All combinations of list wIthout itertools

I'm trying to make a recursive function that finds all the combinations of a python list.
I want to input ['a','b','c'] in my function and as the function runs I want the trace to look like this:
['a','b','c']
['['a','a'],['b','a'],['c','a']]
['['a','a','b'],['b','a','b'],['c','a','b']]
['['a','a','b','c'],['b','a','b','c'],['c','a','b','c']]
My recursive function looks like this:
def combo(lst,new_lst = []):
for item in lst:
new_lst.append([lst[0],item])
print([lst[0],item])
return combo(new_lst,lst[1:])
The right answer is that you should use itertools.combinations. But if for some reason you don't want to, and want to write a recursive function, you can use the following piece of code. It is an adaptation of the erlang way of generating combinations, so it may seem a bit weird at first:
def combinations(N, iterable):
if not N:
return [[]]
if not iterable:
return []
head = [iterable[0]]
tail = iterable[1:]
new_comb = [ head + list_ for list_ in combinations(N - 1, tail) ]
return new_comb + combinations(N, tail)
This a very elegant way of thinking of combinations of size N: you take the first element of an iterable (head) and combine it with smaller (N-1) combinations of the rest of the iterable (tail). Then you add same size (N) combinations of the tail to that. That's how you get all possible combinations.
If you need all combinations, of all lengths you would do:
for n in range(1, len(iterable) + 1):
print(combinations(n, iterable))
Seems that you want all the product of a list, you can use itertools.product within the following function to return a list of generators:
>>> from itertools import product
>>> def pro(li):
... return [product(l,repeat=i) for i in range(2,len(l)+1)]
...
>>> for i in pro(l):
... print list(i)
...
[('a', 'a'), ('a', 'b'), ('a', 'c'), ('b', 'a'), ('b', 'b'), ('b', 'c'), ('c', 'a'), ('c', 'b'), ('c', 'c')]
[('a', 'a', 'a'), ('a', 'a', 'b'), ('a', 'a', 'c'), ('a', 'b', 'a'), ('a', 'b', 'b'), ('a', 'b', 'c'), ('a', 'c', 'a'), ('a', 'c', 'b'), ('a', 'c', 'c'), ('b', 'a', 'a'), ('b', 'a', 'b'), ('b', 'a', 'c'), ('b', 'b', 'a'), ('b', 'b', 'b'), ('b', 'b', 'c'), ('b', 'c', 'a'), ('b', 'c', 'b'), ('b', 'c', 'c'), ('c', 'a', 'a'), ('c', 'a', 'b'), ('c', 'a', 'c'), ('c', 'b', 'a'), ('c', 'b', 'b'), ('c', 'b', 'c'), ('c', 'c', 'a'), ('c', 'c', 'b'), ('c', 'c', 'c')]

Permutation with redundant overlaps? Python

I used itertools to run a permutation on a list that I have.
mylist = [a, b, c, d, e, f]
mypermutations = itertools.permutations(mylist,2)
mypermutations_list = list(mypermutations)
print mypermutations_list
prints:
[(a, b), (a, c), (a, d)...]
However, the permutation list doesn't include (a, a), (b, b), etc. I recognize that's probably because most people don't want such redundant pairings. However, I would like to include such pairings as a control for the program I'm writing.
Is there a way to run a permutation and get these combinations? I have no idea what to use instead of permutations.
You want itertools.product instead:
>>> import itertools
>>> mylist = ['a', 'b', 'c', 'd', 'e', 'f']
>>> list(itertools.product(mylist, repeat=2))
[('a', 'a'), ('a', 'b'), ('a', 'c'), ...]
You're looking for itertools.product, it returns the Cartesian product of the iterable:
>>> from itertools import product
>>> list(product('abcdef', repeat=2))
[('a', 'a'), ('a', 'b'), ('a', 'c'), ('a', 'd'), ('a', 'e'), ('a', 'f'), ('b', 'a'), ('b', 'b'), ('b', 'c'), ('b', 'd'), ('b', 'e'), ('b', 'f'), ('c', 'a'), ('c', 'b'), ('c', 'c'), ('c', 'd'), ('c', 'e'), ('c', 'f'), ('d', 'a'), ('d', 'b'), ('d', 'c'), ('d', 'd'), ('d', 'e'), ('d', 'f'), ('e', 'a'), ('e', 'b'), ('e', 'c'), ('e', 'd'), ('e', 'e'), ('e', 'f'), ('f', 'a'), ('f', 'b'), ('f', 'c'), ('f', 'd'), ('f', 'e'), ('f', 'f')]

Python fastest method to group pairs from a list of items

As a part of my project, I need to group characters as pairs (unique). I have more than 1000 of these characters in a list. What would be the fastest and optimized method to create unique pairs out of these list of characters. I am using itertools currently and my code seems to perform pretty badly.
My Code using itertools:
import itertools
characters = ['A', 'B', 'C', 'D', 'E']
relations = []
for character in range(len(characters) + 1):
for combination in itertools.combinations(characters, character):
if len(combination) == 2:
relations.append(combination)
print relations
Expected Output:
[('A', 'B'), ('A', 'C'), ('A', 'D'), ('A', 'E'), ('B', 'C'),
('B', 'D'), ('B', 'E'), ('C', 'D'), ('C', 'E'), ('D', 'E')]
All you need are combinations of length 2?
In [48]: characters = ['A', 'B', 'C', 'D', 'E']
In [50]: list(itertools.combinations(characters, 2))
Out[50]:
[('A', 'B'),
('A', 'C'),
('A', 'D'),
('A', 'E'),
('B', 'C'),
('B', 'D'),
('B', 'E'),
('C', 'D'),
('C', 'E'),
('D', 'E')]
You are also generating combinations of length 3 to len(characters) and throwing them all away.
characters = ['A', 'B', 'C', 'D', 'E']
relations = list(itertools.combinations(characters, 2))

From a combination, get subsets with members containing the same first element, python

Suppose I have the following list:
ls = ['a', 'b', 'c', 'd']
I get a combination using
list(itertools.combinations(iterable, 2))
>>> [('a', 'b'), ('a', 'c'), ('a', 'd'), ('b', 'c'), ('b', 'd'), ('c', 'd')]
What I'd like to do is break this combination into subsets, such that the first member of each tuple in the subset is the same:
subset1: [('a', 'b'), ('a', 'c'), ('a', 'd')]
subset2: [('b', 'c'), ('b', 'd'),
subset3: [('c', 'd')]
Any ideas?
>>> import itertools as it
>>> ls = ['a', 'b', 'c', 'd']
>>> ii=it.groupby( it.combinations(ls, 2), lambda x: x[0] )
>>> for key, iterator in ii:
... print key, list(iterator)
...
a [('a', 'b'), ('a', 'c'), ('a', 'd')]
b [('b', 'c'), ('b', 'd')]
c [('c', 'd')]
If you don't like lambda, you could use operator.itemgetter(0) instead of lambda x: x[0].
subset = [('a', 'b'), ('a', 'c'), ('a', 'd'), ('b', 'c'), ('b', 'd'), ('c', 'd')]
subsets = [[x for x in subset where x[0] == y] for y in ['a','b','c']]
try this:
[filter(lambda k:k[0]==p,comb) for p in ls]
where:
ls = ['a', 'b', 'c', 'd']
comb = [('a', 'b'), ('a', 'c'), ('a', 'd'), ('b', 'c'), ('b', 'd'), ('c', 'd')]
the output is:
[[('a', 'b'), ('a', 'c'), ('a', 'd')], [('b', 'c'), ('b', 'd')], [('c', 'd')], []]

Categories

Resources