Python itertools combinations customizing - python

I am doing a question based on combinations and just stuck in it. And yes I am not so good in python.
The itertools combinations function using ncr just return the r possible combinations from n. I want something which will return the r possible combinations selected and also the other remaining elements from n numbers which were not selected in that iteration.
Example:
>>>from itertools import combinations
>>>list = [1, 2, 3, 4, 5]
>>>rslt = combinations(list, 2)
when [2, 4] is selected it should also return [1, 3, 5]
so it should return like [[2, 4], [1, 3, 5]]
Thanks in advance

itertools.combinations
Return r length subsequences of elements from the input iterable.
You can use a list comprehension to get the other items [j for j in l if j not in i]:
from itertools import combinations
l = [1, 2, 3, 4, 5]
for i in combinations(l,2):
print(list(i),[j for j in l if j not in i])
And you will get :
[1, 2] [3, 4, 5]
[1, 3] [2, 4, 5]
[1, 4] [2, 3, 5]
[1, 5] [2, 3, 4]
[2, 3] [1, 4, 5]
[2, 4] [1, 3, 5]
[2, 5] [1, 3, 4]
[3, 4] [1, 2, 5]
[3, 5] [1, 2, 4]
[4, 5] [1, 2, 3]
By the way, it's not recommended to use list as a variable name.

The simplest way would be to make a copy of the original list, removing the elements that are in the combination:
from itertools import combinations
def combinations_and_remaining(l, n):
for c in combinations(l, n):
diff = [i for i in l if i not in c]
yield c, diff
for i in combinations_and_remaining([1, 2, 3, 4, 5], 2):
print(i)
Will output
((1, 2), [3, 4, 5])
((1, 3), [2, 4, 5])
((1, 4), [2, 3, 5])
((1, 5), [2, 3, 4])
((2, 3), [1, 4, 5])
((2, 4), [1, 3, 5])
((2, 5), [1, 3, 4])
((3, 4), [1, 2, 5])
((3, 5), [1, 2, 4])
((4, 5), [1, 2, 3])
(The combinations returns tuples; remaining elements are returned as lists for efficiency)

One slightly extravagant but fun way would be to use combinations twice:
from itertools import combinations
n = 5
k = 2
lst = list(range(1, n+1))
rslt = zip(combinations(lst, k), map(tuple, reversed(list(combinations(lst, n-k)))))
print(list(rslt))
# -> [((1, 2), (3, 4, 5)), ((1, 3), (2, 4, 5)), ((1, 4), (2, 3, 5)),
# ((1, 5), (2, 3, 4)), ((2, 3), (1, 4, 5)), ((2, 4), (1, 3, 5)),
# ((2, 5), (1, 3, 4)), ((3, 4), (1, 2, 5)), ((3, 5), (1, 2, 4)),
# ((4, 5), (1, 2, 3))]

You can avoid loops and improve readability by using sets, as such:
from itertools import combinations
input = [1,2,3,4,5]
for n in itertools.combinations(input, 2):
print(n , set(n) ^ set(input))
That is, of course, assuming there are no duplicates in the original, which will be lost in the conversion to a set.

Related

All Possible Combinations Python [duplicate]

This question already has answers here:
How to get all possible combinations of a list’s elements?
(32 answers)
Power set and Cartesian Product of a set python
(1 answer)
Closed 1 year ago.
So say you have n numbers in a list as so
[n1, n2, n3, ...., n]
How would you get all possible combinations?
For example if you had
[1,2,3,4]
You return a list like:
[[1,2], [1,3], [1,4], [2,3], [2,4], [3,4], [1,2,3], [1,2,4], [1,3,4], [2, 3, 4], [1,2,3,4]]
Here is a generator function, using the go-to itertools.combinations:
from itertools import combinations
def combos(lst):
for n in range(2, len(lst)+1):
yield from combinations(lst, n)
list(combos([1,2,3,4]))
# [(1, 2), (1, 3), (1, 4), (2, 3), (2, 4), (3, 4),
# (1, 2, 3), (1, 2, 4), (1, 3, 4), (2, 3, 4),
# (1, 2, 3, 4)]
If you desperately need lists instead of tuples:
list(map(list, combos([1,2,3,4])))
# [[1, 2], [1, 3], [1, 4], [2, 3], [2, 4], [3, 4],
# [1, 2, 3], [1, 2, 4], [1, 3, 4], [2, 3, 4],
# [1, 2, 3, 4]]

how to permute n elements from list recursively in python?

I'm trying to figure out how to create all possible n sized permutations from a list recursively.
For example the result of n=2 and list=[0,1,5] would be:
[[0, 0], [1, 0], [5, 0], [0, 1], [1, 1], [5, 1], [0, 5], [1, 5], [5, 5]]
or n=3 and list=[2,3]:
[[2, 2, 2], [3, 2, 2], [2, 3, 2], [3, 3, 2], [2, 2, 3], [3, 2, 3], [2, 3, 3], [3, 3, 3]]
(sort of like cartesian product).
I've managed to come up with this piece of code:
def perm(nlist, m):
if m > len(nlist):
return
if m == 0 or m == len(nlist):
return [[]]
results = []
for list_i in nlist:
temp = list(nlist)
temp.remove(list_i)
results.extend(map(lambda x: [list_i] + x, perm(temp, m-1)))
return results
but it doesn't give permutations like [0,0] [1,1] [2,2] etc.
Does anybody have a solution for me?
How can I make this without using map() and lambda()?
This isn't sort of like cartesian product; it's exactly like cartesian product.
>>> from itertools import product
>>> list(product([0,1,5], repeat=2))
[(0, 0), (0, 1), (0, 5), (1, 0), (1, 1), (1, 5), (5, 0), (5, 1), (5, 5)]
>>> list(product([2,3], repeat=3))
[(2, 2, 2), (2, 2, 3), (2, 3, 2), (2, 3, 3), (3, 2, 2), (3, 2, 3), (3, 3, 2), (3, 3, 3)]
The polyfill for itertools.product is the following:
def product(*args, **kwds):
# product('ABCD', 'xy') --> Ax Ay Bx By Cx Cy Dx Dy
# product(range(2), repeat=3) --> 000 001 010 011 100 101 110 111
pools = map(tuple, args) * kwds.get('repeat', 1)
result = [[]]
for pool in pools:
result = [x+[y] for x in result for y in pool]
for prod in result:
yield tuple(prod)
But since you can't use itertools, you might as well take the liberty of writing a slightly more efficient solution to your problem. Since we are just computing the product of n identical iterables, let's just call it a cartesian exponent:
def cartesian_exponent(li, e=1):
pools = [li] * e
result = [[]]
for pool in pools:
result = [x+[y] for x in result for y in pool]
return result
Or recursively using yet another incomprehensible list comprehension:
def cartesian_exponent(li, e=1):
if e == 1:
return [[x] for x in li]
else:
return [[x]+y for x in li for y in cartesian_exponent(li, e=e-1)]
Which can be compressed to one line:
def cartesian_exponent(li, e=1):
return [[x] for x in li] if e == 1 else [[x] + y for x in li for y in cartesian_exponent(li, e=e-1)]
But then you would be sacrificing readability for terseness and that's no bueno. The incomprehensible list comprehension is already opaque enough.
Some tests:
>>> cartesian_exponent([0,1,5], e=2)
[[0, 0], [0, 1], [0, 5], [1, 0], [1, 1], [1, 5], [5, 0], [5, 1], [5, 5]]
>>> cartesian_exponent([2,3], e=3)
[[2, 2, 2], [2, 2, 3], [2, 3, 2], [2, 3, 3], [3, 2, 2], [3, 2, 3], [3, 3, 2], [3, 3, 3]]
The result you are looking for is the Cartesian product which is the set of all ordered pairs (a, b) where a ∈ A and b ∈ B. Or, all permutations of all combinations.
from itertools import combinations_with_replacement as iter_combs
from itertools import permutations
def perms_combs(l, n):
all_combs = []
for l in list(iter_combs(l, n)):
[all_combs.append(perm) for perm in list(permutations(l, n))]
return list(set(all_combs))
>> print list(product([0, 1, 5], repeat=2))
[(0, 0), (0, 0), (0, 1), (1, 0), (0, 5), (5, 0), (1, 1), (1, 1), (1, 5), (5, 1), (5, 5), (5, 5)]
>> print list(product([2, 3], repeat=3))
[(3, 3, 3), (2, 2, 2), (2, 3, 2), (3, 3, 2), (2, 3, 3), (3, 2, 2), (3, 2, 3), (2, 2, 3)]
This process, however, is already covered by an itertools functions: product
from itertools import product
>> print product([0, 1, 5], 2)
[(0, 0), (0, 0), (0, 1), (1, 0), (0, 5), (5, 0), (1, 1), (1, 1), (1, 5), (5, 1), (5, 5), (5, 5)]
>> print product([2, 3], 3)
[(3, 3, 3), (2, 2, 2), (2, 3, 2), (3, 3, 2), (2, 3, 3), (3, 2, 2), (3, 2, 3), (2, 2, 3)]

Creating sub-lists from a list

I am trying to create a list containing sub-lists in python; like, the proper subset of a set. For example,
A = [1, 2, 3, 4]
Desired List = [[1, 2], [1, 3], [1, 4], [2, 3], [2, 4], [3, 4], [1, 2, 3], [1, 2, 4], [2, 3, 4]]
Thanks!
Since it seems you only want subsets of size 2 or more:
from itertools import combinations, chain
A = range(1, 5)
list(chain(*(combinations(A, r) for r in range(2, len(A)))))
# [(1, 2), (1, 3), (1, 4), (2, 3), (2, 4), (3, 4), (1, 2, 3), (1, 2, 4), (1, 3, 4), (2, 3, 4)]
If you want all proper subsets, just change range(2, len(A)) to range(len(A)).
It looks like you want to get all the combinations from the list. Try using itertools.combinations
desired_list = itertools.combinations(A, 2)

Create all combinations of lists from a list of lists in python

I have a list: l = [1, (2, 3), (4, 5), 6]
I want to choose 3 items from this list, but only one item can be chosen for each sub list.
Using combinations I can achieve:
Result = [[1, (2, 3), (4, 5)], [1, (2, 3), 6], [1, (4, 5), 6]]
However the tuples are not expanded. What is the most Pythonic way to produce a list of all the combinations of items within that list?
Example output:
Result = [[1, 2, 4], [1, 2, 5], [1, 2, 6], [1, 3, 4], [1, 3, 5], [1, 3, 6], [2, 4, 6], [2, 5, 6], [3, 4, 6], [3, 5, 6]]
You could combine combinations with product:
>>> from itertools import combinations, product
>>> seq = [1, (2, 3), (4, 5), 6]
>>> seq = [x if isinstance(x, tuple) else (x,) for x in seq]
>>> [sel for subseq in combinations(seq, 3) for sel in product(*subseq)]
[(1, 2, 4), (1, 2, 5), (1, 3, 4), (1, 3, 5), (1, 2, 6), (1, 3, 6), (1, 4, 6), (1, 5, 6), (2, 4, 6), (2, 5, 6), (3, 4, 6), (3, 5, 6)]
where I've converted seq to be a list of tuples (even if the tuples only have one element) first, because that makes later operations much more natural.

Select adjacent couples (or triads, etc ) from a list

I can do it by making use of the list indexes ...
lst =[1,2,3,4,5,6]
[ [lst[i] , lst[i+1]] for i in range( len(lst) - 1 )]
or:
lst =[1,2,3,4,5,6]
for i in range(len(lst)-1):
entities.append([lst[i],lst[i+1]])
But is there a smarter way? Maybe using iterators? What about performance?
For a general solution (since you asked for couples, triples, etc.), use itertools.tee:
from itertools import tee
def adjacent_tuples(iterable, n=2):
iterators = tee(iterable, n)
for i, iterator in enumerate(iterators):
for j in range(i):
next(iterator)
return zip(*iterators)
This uses a minimum of memory and works for any length of tuples:
>>> list(adjacent_tuples(range(8), 4))
[(0, 1, 2, 3), (1, 2, 3, 4), (2, 3, 4, 5), (3, 4, 5, 6), (4, 5, 6, 7)]
You received some clever answers here, but I'd like to suggest that the most obvious way to do this just uses built-in slice indexing. Like so:
def gen_k_slices(seq, k):
for i in range(len(seq) - k + 1):
yield seq[i:i+k]
Here's a little test driver:
TEST = [1, 2, 3, 4, 5, 6]
for k in range(8):
print("k={} -> {}".format(k, list(gen_k_slices(TEST, k))))
and its output:
k=0 -> [[], [], [], [], [], [], []]
k=1 -> [[1], [2], [3], [4], [5], [6]]
k=2 -> [[1, 2], [2, 3], [3, 4], [4, 5], [5, 6]]
k=3 -> [[1, 2, 3], [2, 3, 4], [3, 4, 5], [4, 5, 6]]
k=4 -> [[1, 2, 3, 4], [2, 3, 4, 5], [3, 4, 5, 6]]
k=5 -> [[1, 2, 3, 4, 5], [2, 3, 4, 5, 6]]
k=6 -> [[1, 2, 3, 4, 5, 6]]
k=7 -> []
I don't like the result for k=0 either ;-)
You can use zip():
>>> lst = [1,2,3,4,5,6]
>>> list(zip(lst[:-1],lst[1:]))
[(1, 2), (2, 3), (3, 4), (4, 5), (5, 6)]
>>> list(zip(lst[:-2],lst[1:-1],lst[2:]))
[(1, 2, 3), (2, 3, 4), (3, 4, 5), (4, 5, 6)]
An iterator would be like this.
def iterate_couples(lst):
for i in range(len(lst) - 1):
yield [lst[i], lst[i + 1]]
You can zip iterators, one regular and another one shifted:
>>> it = iter(lst)
>>> it.next()
1
>>> zip(iter(lst), it)
[(1, 2), (2, 3), (3, 4), (4, 5), (5, 6)]
Here's an appropriate generator (using izip):
from itertools import izip
def my_zip(l):
i1 = iter(l)
i2 = iter(l)
i2.next()
for value in izip(i1, i2):
yield value
lst = [1,2,3,4,5,6]
print list(my_zip(lst)) # prints [(1, 2), (2, 3), (3, 4), (4, 5), (5, 6)]

Categories

Resources