Making all possible combinations of a list [duplicate] - python

This question already has answers here:
How to get all possible combinations of a list’s elements?
(32 answers)
Closed 8 months ago.
I need to be able to make a list that contains all possible combinations of an inputted list.
For example the list [1,2,3] should return [1 [1,2] [1,3] 2 [2,3] 3 [1,2,3]]
The list doesn't have to be in any particular order. On this site I've found lots of functions using the itertools but those are returning objects when I need just a list.

Simply use itertools.combinations. For example:
import itertools
lst = [1, 2, 3]
combs = []
for i in xrange(1, len(lst)+1):
combs.append(i)
els = [list(x) for x in itertools.combinations(lst, i)]
combs.append(els)
Now combs holds this value:
[1, [[1], [2], [3]], 2, [[1, 2], [1, 3], [2, 3]], 3, [[1, 2, 3]]]
Yes, it's slightly different from the sample output you provided, but in that output you weren't listing all possible combinations.
I'm listing the size of the combination before the actual list for each size, if what you need is simply the combinations (without the size, as it appears in your sample output) then try these other version of the code:
import itertools
lst = [1, 2, 3]
combs = []
for i in xrange(1, len(lst)+1):
els = [list(x) for x in itertools.combinations(lst, i)]
combs.extend(els)
Now combs holds this value:
[[1], [2], [3], [1, 2], [1, 3], [2, 3], [1, 2, 3]]

The itertools module indeed returns generators instead of lists, but:
Generators are often more efficient than lists (especially if you are generating a large number of combinations)
You can always convert generators to lists using list(...) when you really need to.
The chain and combinations functions of itertools work well, but you need to use Python 2.6 or greater:
import itertools
def all_combinations(any_list):
return itertools.chain.from_iterable(
itertools.combinations(any_list, i + 1)
for i in xrange(len(any_list)))
You can then call this as such:
# as a generator
all_combinations([1,2,3]) # --> <itertools.chain at 0x10ef7ce10>
# as a list
list(all_combinations([1,2,3])) # --> [(1,), (2,), (3,), (1, 2), (1, 3), (2, 3), (1, 2, 3)]
# as a list of lists
[list(l) for l in all_combinations([1,2,3])] # --> [[1], [2], [3], [1, 2], [1, 3], [2, 3], [1, 2, 3]]
If you haven't used generators before, note that you loop through them as if they were a list, such as this:
# a generator returned instead of list
my_combinations = all_combinations([1,2,3])
# this would also work if `my_combinations` were a list
for c in my_combinations:
print "Combo", c
"""
Prints:
Combo (1,)
Combo (2,)
Combo (3,)
Combo (1, 2)
Combo (1, 3)
Combo (2, 3)
Combo (1, 2, 3)
"""
The performance difference can be dramatic. If you compare the performance you'll see that the generator is much faster to create:
# as a generator
all_combinations(range(25)) # timing: 100000 loops, best of 3: 2.53 µs per loop
# as a list
list(all_combinations(range(25))) # timing: 1 loops, best of 3: 9.37 s per loop
Note that it would still take some time to iterate through all the combinations in either case, but it can be a big win for you especially if you find what you're looking for early on.

The functions from the itertools module return iterators. All you need to do to convert these into lists is call list() on the result.
However, since you will need to call itertools.combinations three separate times (once for each different length), you can just use list.extend to add all elements of the iterator to your final list.
Try the following:
import itertools
in_list = [1, 2, 3]
out_list = []
for i in range(1, len(in_list)+1):
out_list.extend(itertools.combinations(in_list, i))
Or as a list comprehension:
out_list = [c for i in range(len(in_list)) for c in itertools.combinations(in_list, i+1)]
These will result in the following list:
[(1,), (2,), (3,), (1, 2), (1, 3), (2, 3), (1, 2, 3)]
If you want lists instead of tuples, and to convert the single length tuples to just the value, you can do the following:
out_list = [x[0] if len(x) == 1 else list(x) for x in out_list]
# [1, 2, 3, [1, 2], [1, 3], [2, 3], [1, 2, 3]]
Or to leave the single items as lists:
out_list = map(list, out_list)

You could solve your problem using itertools.combinations inside of a loop:
>>> l = [1,2,3]
>>> comb = []
>>> for i in range(len(l)):
... comb += itertools.combinations(l,i+1)
...
>>> comb
[(1,), (2,), (3,), (1, 2), (1, 3), (2, 3), (1, 2, 3)]
And if you want them as a list:
>>> comb_list = [ list(t) for t in comb ]
>>> comb_list
[[1], [2], [3], [1, 2], [1, 3], [2, 3], [1, 2, 3]]
EDIT: The first parameter of combinations is the iterable and the second one is the length of the resulting tuples (in this case, going from 1 to len(l)).
More about combinations: http://docs.python.org/library/itertools.html#itertools.combinations

l = [1,2,3]
combs = reduce(lambda x, y: list(itertools.combinations(l, y)) + x, range(len(l)+1), [])
If you want a oneliner.

I think it's worth boiling down the other answers here into a simple Python 3 example:
from itertools import chain, combinations
def all_combinations(array):
return chain(*(list(combinations(array, i + 1)) for i in range(len(array))))
This returns an iterable, to view the values:
>>> print(list(all_combinations((1, 2, 3))))
[(1,), (2,), (3,), (1, 2), (1, 3), (2, 3), (1, 2, 3)]

Related

Using min and max on sublists and creating a list without using "for loop" outside reduce function

from functools import reduce
for _ in range(int(input())):
N = int(input())
l1 = list(map(int,input().split()))
def powerset(lst):
return reduce(lambda result, x: result + [subset + [x] for subset in result],
lst, [[]])
#https://stackoverflow.com/questions/1482308/how-to-get-all-subsets-of-a-set-powerset
lst = (powerset(l1))
print(lst)
ivlst = []
for i in range(1, len(lst)):
ivlst.append((min(lst[i])*max(lst[i])))
print(min(ivlst), end=" ")
print(max(ivlst))
Sample input:
2
2
2 2
3
5 0 9
Sample output:
4 4
0 81
The above code does the following:
It takes the input as N, where N is the number of elements in the list.
Then it takes the input as the elements of the list.
Then it creates a function called powerset which takes a list as an argument and returns all the subsets of that list.
Then it calls the reduce function on the powerset function with the list as the first argument and the empty list as the second argument.
The reduce function will return a list of lists.
The ivlst variable is used to store the values of the minimum and maximum of the subsets.
Then it iterates over the range from 1 to the length of the list.
For each iteration, it appends the multiplication of minimum and maximum of the subset to the ivlst list.
Finally, it prints the minimum and maximum of the ivlst list.
The time complexity is O(2^n) where n is the number of elements in the given set.
I need a way to not use the for loop for getting the min and max values of all sublists, rather I need to get a list containing multiplication of min and max values of all sublists as output from the powerset function itself.
You could maximize the production of the powerset function, in fact,
the Python itertools page has exactly a powerset recipe:
def powerset(iterable):
"powerset([1,2,3]) --> () (1,) (2,) (3,) (1,2) (1,3) (2,3) (1,2,3)"
s = list(iterable)
return chain.from_iterable(combinations(s, r) for r in range(len(s)+1))
or you can achieve by:
from more_itertools import powerset
The equivalent code of your powerset function is as follows:
from itertools import islice
def powerset(lst):
ret = [[]]
for elem in lst:
for subset in islice(ret, len(ret)):
ret.append(subset + [elem])
return ret
We no longer build and record the remaining subsets in the inner loop, but only record the minimum and maximum values of the subsets, so that our operating costs will be greatly reduced (from O(n * 2^n) to O(2^n), because the generation algorithm of power sets will not be faster than O(2^n), and the minimum and maximum values calculated for each subset are O(n)):
from itertools import islice
def powerset_extremum(lst):
ret = [(float('inf'), float('-inf'))]
for elem in lst:
for min_, max_ in islice(ret, len(ret)):
ret.append((min(min_, elem), max(max_, elem)))
return ret
Simple test:
>>> powerset([2, 1, 4, 3])
[[],
[2],
[1],
[2, 1],
[4],
[2, 4],
[1, 4],
[2, 1, 4],
[3],
[2, 3],
[1, 3],
[2, 1, 3],
[4, 3],
[2, 4, 3],
[1, 4, 3],
[2, 1, 4, 3]]
>>> powerset_extremum([2, 1, 4, 3])
[(inf, -inf),
(2, 2),
(1, 1),
(1, 2),
(4, 4),
(2, 4),
(1, 4),
(1, 4),
(3, 3),
(2, 3),
(1, 3),
(1, 3),
(3, 4),
(2, 4),
(1, 4),
(1, 4)]
Then you can easily get their multiplication:
>>> from itertools import starmap, islice
>>> from operator import mul
>>> list(starmap(mul, islice(powerset_extremum([2, 1, 4, 3]), 1, None)))
[4, 1, 2, 16, 8, 4, 4, 9, 6, 3, 3, 12, 8, 4, 4]
I know that this does not meet your requirement of not using the for loop, but it is obviously much faster than eliminating the explicit for loop through some built-in functions after getting the power set.

how to get all possible combinations of different lengths of all list items without using itertools Python [duplicate]

This question already has answers here:
How to get all possible combinations of a list’s elements?
(32 answers)
Closed 8 months ago.
I need to be able to make a list that contains all possible combinations of an inputted list.
For example the list [1,2,3] should return [1 [1,2] [1,3] 2 [2,3] 3 [1,2,3]]
The list doesn't have to be in any particular order. On this site I've found lots of functions using the itertools but those are returning objects when I need just a list.
Simply use itertools.combinations. For example:
import itertools
lst = [1, 2, 3]
combs = []
for i in xrange(1, len(lst)+1):
combs.append(i)
els = [list(x) for x in itertools.combinations(lst, i)]
combs.append(els)
Now combs holds this value:
[1, [[1], [2], [3]], 2, [[1, 2], [1, 3], [2, 3]], 3, [[1, 2, 3]]]
Yes, it's slightly different from the sample output you provided, but in that output you weren't listing all possible combinations.
I'm listing the size of the combination before the actual list for each size, if what you need is simply the combinations (without the size, as it appears in your sample output) then try these other version of the code:
import itertools
lst = [1, 2, 3]
combs = []
for i in xrange(1, len(lst)+1):
els = [list(x) for x in itertools.combinations(lst, i)]
combs.extend(els)
Now combs holds this value:
[[1], [2], [3], [1, 2], [1, 3], [2, 3], [1, 2, 3]]
The itertools module indeed returns generators instead of lists, but:
Generators are often more efficient than lists (especially if you are generating a large number of combinations)
You can always convert generators to lists using list(...) when you really need to.
The chain and combinations functions of itertools work well, but you need to use Python 2.6 or greater:
import itertools
def all_combinations(any_list):
return itertools.chain.from_iterable(
itertools.combinations(any_list, i + 1)
for i in xrange(len(any_list)))
You can then call this as such:
# as a generator
all_combinations([1,2,3]) # --> <itertools.chain at 0x10ef7ce10>
# as a list
list(all_combinations([1,2,3])) # --> [(1,), (2,), (3,), (1, 2), (1, 3), (2, 3), (1, 2, 3)]
# as a list of lists
[list(l) for l in all_combinations([1,2,3])] # --> [[1], [2], [3], [1, 2], [1, 3], [2, 3], [1, 2, 3]]
If you haven't used generators before, note that you loop through them as if they were a list, such as this:
# a generator returned instead of list
my_combinations = all_combinations([1,2,3])
# this would also work if `my_combinations` were a list
for c in my_combinations:
print "Combo", c
"""
Prints:
Combo (1,)
Combo (2,)
Combo (3,)
Combo (1, 2)
Combo (1, 3)
Combo (2, 3)
Combo (1, 2, 3)
"""
The performance difference can be dramatic. If you compare the performance you'll see that the generator is much faster to create:
# as a generator
all_combinations(range(25)) # timing: 100000 loops, best of 3: 2.53 µs per loop
# as a list
list(all_combinations(range(25))) # timing: 1 loops, best of 3: 9.37 s per loop
Note that it would still take some time to iterate through all the combinations in either case, but it can be a big win for you especially if you find what you're looking for early on.
The functions from the itertools module return iterators. All you need to do to convert these into lists is call list() on the result.
However, since you will need to call itertools.combinations three separate times (once for each different length), you can just use list.extend to add all elements of the iterator to your final list.
Try the following:
import itertools
in_list = [1, 2, 3]
out_list = []
for i in range(1, len(in_list)+1):
out_list.extend(itertools.combinations(in_list, i))
Or as a list comprehension:
out_list = [c for i in range(len(in_list)) for c in itertools.combinations(in_list, i+1)]
These will result in the following list:
[(1,), (2,), (3,), (1, 2), (1, 3), (2, 3), (1, 2, 3)]
If you want lists instead of tuples, and to convert the single length tuples to just the value, you can do the following:
out_list = [x[0] if len(x) == 1 else list(x) for x in out_list]
# [1, 2, 3, [1, 2], [1, 3], [2, 3], [1, 2, 3]]
Or to leave the single items as lists:
out_list = map(list, out_list)
You could solve your problem using itertools.combinations inside of a loop:
>>> l = [1,2,3]
>>> comb = []
>>> for i in range(len(l)):
... comb += itertools.combinations(l,i+1)
...
>>> comb
[(1,), (2,), (3,), (1, 2), (1, 3), (2, 3), (1, 2, 3)]
And if you want them as a list:
>>> comb_list = [ list(t) for t in comb ]
>>> comb_list
[[1], [2], [3], [1, 2], [1, 3], [2, 3], [1, 2, 3]]
EDIT: The first parameter of combinations is the iterable and the second one is the length of the resulting tuples (in this case, going from 1 to len(l)).
More about combinations: http://docs.python.org/library/itertools.html#itertools.combinations
l = [1,2,3]
combs = reduce(lambda x, y: list(itertools.combinations(l, y)) + x, range(len(l)+1), [])
If you want a oneliner.
I think it's worth boiling down the other answers here into a simple Python 3 example:
from itertools import chain, combinations
def all_combinations(array):
return chain(*(list(combinations(array, i + 1)) for i in range(len(array))))
This returns an iterable, to view the values:
>>> print(list(all_combinations((1, 2, 3))))
[(1,), (2,), (3,), (1, 2), (1, 3), (2, 3), (1, 2, 3)]

How can one generate all possible teams of players from a list?

I have a list of, say, 3 players:
[1, 2, 3]
How can I generate, in python, a list of lists, of the form:
[[1], [2], [3], [1,2], [1,3], [2,3], [1,2,3]]
representing all teams that can be formed with the above players?
You could use itertools.combinations() where we can set r parameter to all lengths from 1 to length of our list (x), to get all possible combinations that are going to be flattened in list comprehension.
from itertools import combinations
x = [1, 2, 3]
result = [c for i in range(1, len(x)+1) for c in combinations(x, i)]
print(result) # -> [(1,), (2,), (3,), (1, 2), (1, 3), (2, 3), (1, 2, 3)]
Use https://docs.python.org/3/library/itertools.html#itertools.combinations
It does exactly what you want.
import itertools
players = [1, 2, 3]
print(list(itertools.chain.from_iterable(itertools.combinations(players, r) for r in range(1, len(players) + 1))))
Output:
[(1,), (2,), (3,), (1, 2), (1, 3), (2, 3), (1, 2, 3)]
This is probably the most efficient answer due to the use of itertools.chain
You can use itertools.combinations with a given size to generate fixed size combinations. In order to generalize, you can just use a for loop over all the sizes. The code would look like this:
import itertools
my_list = [1, 2, 3]
for L in range(0, len(my_list)+1):
for subset in itertools.combinations(my_list, L):
print(subset)
Itertools is you friend for these kind of operations:
import itertools
l = [1, 2, 3]
l = [list(x) for y in range(1,len(l)+1) for x in itertools.combinations(l,y) ]
print(l)
Gives:
[[1], [2], [3], [1, 2], [1, 3], [2, 3], [1, 2, 3]]
You can use itertools. What you want to do is generate powerset of the given list.
>>> import itertools
>>> a=[1,2,3]
>>> out=[]
>>> for i in range(len(a)+1):
out+=list(itertools.combinations(a,i))
>>> out
[(), (1,), (2,), (3,), (1, 2), (1, 3), (2, 3), (1, 2, 3)]
>>>
You can write recursive function to generate powerset as follows:
>>> def powerset(s,idx,curr,out):
if idx==len(s):
out.append(curr)
return
(powerset(s,idx+1,curr+[s[idx]],out))
(powerset(s,idx+1,curr,out))
return sorted(out,key=lambda x:len(x))
>>> z=powerset(a,0,[],[])
>>> z
[[], [1], [2], [3], [1, 2], [1, 3], [2, 3], [1, 2, 3]]

Python | Insert Two Items in a List per Iteration with One-Liner

Is it possible to insert in a list 2 items with one-liner?
For example, get [1, 2, 3, 4] by something like [ x, x+1 for x in [1, 3]]
No you can't do this. Instead you can use a generator expression within itertools.chain.from_iterable in order to chain the iterable items or use a nested list comprehension (which is not as optimized as chain.from_iterable since you have to create the items then unpack them with another loop).
>>> from itertools import chain
>>> l = [(1, 2), (3, 5)]
>>>
>>> list(chain.from_iterable(i for i in l))
[1, 2, 3, 5]
In python 3.5+ you can unpack the iterables within a list like following but still not at iteration time.
>>> a = (1, 2)
>>> b = (3, 5)
>>>
>>> [*a, *b]
[1, 2, 3, 5]
[item for sublist in [ [x, x+1] for x in [1, 3] ] for item in sublist]

Getting the mode from tuples inside lists [duplicate]

How do I convert
[(1,), (2,), (3,)]
to
[1, 2, 3]
Using simple list comprehension:
e = [(1,), (2,), (3,)]
[i[0] for i in e]
will give you:
[1, 2, 3]
#Levon's solution works perfectly for your case.
As a side note, if you have variable number of elements in the tuples, you can also use chain from itertools.
>>> a = [(1, ), (2, 3), (4, 5, 6)]
>>> from itertools import chain
>>> list(chain(a))
[(1,), (2, 3), (4, 5, 6)]
>>> list(chain(*a))
[1, 2, 3, 4, 5, 6]
>>> list(chain.from_iterable(a)) # More efficient version than unpacking
[1, 2, 3, 4, 5, 6]
Here is another alternative if you can have a variable number of elements in the tuples:
>>> a = [(1,), (2, 3), (4, 5, 6)]
>>> [x for t in a for x in t]
[1, 2, 3, 4, 5, 6]
This is basically just a shortened form of the following loops:
result = []
for t in a:
for x in t:
result.append(x)
>>> a = [(1,), (2,), (3,)]
>>> zip(*a)[0]
(1, 2, 3)
For a list:
>>> list(zip(*a)[0])
[1, 2, 3]
>>> a = [(1,), (2,), (3,)]
>>> b = map(lambda x: x[0], a)
>>> b
[1, 2, 3]
With python3, you have to put the list(..) function to the output of map(..), i.e.
b = list(map(lambda x: x[0], a))
This is the best solution in one line using python built-in functions.
You can also use sum function as follows:
e = [(1,), (2,), (3,)]
e_list = list(sum(e, ()))
And it also works with list of lists to convert it into a single list, but you will need to use it as follow:
e = [[1, 2], [3, 4], [5, 6]]
e_list = list(sum(e, []))
This will give you [1, 2, 3, 4, 5, 6]
There's always a way to extract a list from another list by ...for...in.... In this case it would be:
[i[0] for i in e]
Using operator or sum
>>> from functools import reduce ### If python 3
>>> import operator
>>> a = [(1,), (2,), (3,)]
>>> list(reduce(operator.concat, a))
[1, 2, 3]
(OR)
>>> list(sum(a,()))
[1, 2, 3]
>>>
If in python > 3 please do the import of reduce from functools
like from functools import reduce
https://docs.python.org/3/library/functools.html#functools.reduce
You can also unpack the tuple in the list comprehension:
e = [(1,), (2,), (3,)]
[i for (i,) in e]
will still give:
[1, 2, 3]
One Liner yo!
list(*zip(*[(1,), (2,), (3,)]))
In these situations I like to do:
a = [(1,), (2,), (3,)]
new_a = [element for tup in a for element in tup]
This works even if your tuples have more than one element. This is equivalent to doing this:
a = [(1,), (2,), (3,)]
new_a = []
for tup in a:
for element in tup:
new_a.append(element)
If it is already a numpy array, use ravel() method which is more faster than list comprehension.
If it is already a list, list comprehension is better.
Most of the answers above only prints the first element not all the elements
For numpy arrays
#arr = np.array([(1,2), (2,3), (3,4)])
#faster than list comprehension
arr.ravel().tolist()
#output => [1,2,2,3,3,4]
For list
list_ = [(1,2), (2,3), (3,4)]
[x for y in list_ for x in y]
#output => [1,2,2,3,3,4]

Categories

Resources