How to use combinations - python

I have 6 lists, say,
a=[1,1,0,0]
b=[0,1,1,0]
c=[0,0,1,1]
d .... until f.
I want to generate the results of the sum for all possible combination of the lists starting from 2 lists till 6 lists. For example, I want to calculate the result of a+b, a+c, .. a+f. Then, a+b+c, a+b+d, ...etc. I know hoe to compute the result of two or three lists but I am stuck in how to generate the combinations for lists. I tried to define list of lists and use combinations with argument 2 to generate all possible 2 combinations for 3 lists (as example) as follows:
import itertools
alphabet = [[0,0,0],[0,0,1],[0,1,0]]
combos = itertools.combinations(alphabet, 2)
usable_combos = []
for e in combos:
usable_combos.append(e)
But this simply does not produce anything. When I print usable_combos, I get:
[[0,0,0],[0,0,1],[0,1,0]]
My question is: using combinations, how can I produce all possible combinations (from 2 to 6 combinations) for the 6 different sets I have?

Use range(1, len(lis)+1) to get the value for the second parameter(r) that is passed to combinations. or range(2, len(lis)+1) if you want to start from 2.
>>> from itertools import combinations
>>> lis = [[0,0,0],[0,0,1],[0,1,0]]
>>> for i in range(1, len(lis)+1):
... for c in combinations(lis,i):
... print c
...
([0, 0, 0],)
([0, 0, 1],)
([0, 1, 0],)
([0, 0, 0], [0, 0, 1])
([0, 0, 0], [0, 1, 0])
([0, 0, 1], [0, 1, 0])
([0, 0, 0], [0, 0, 1], [0, 1, 0])
As pointed out may #abarnert in the comment, may be you want this:
>>> from pprint import pprint
>>> from itertools import chain
>>> flatten = chain.from_iterable
>>> ans = [list(flatten(c)) for i in range(2, len(lis)+1) for c in permutations(lis,i)]
>>> pprint(ans)
[[0, 0, 0, 0, 0, 1],
[0, 0, 0, 0, 1, 0],
[0, 0, 1, 0, 0, 0],
[0, 0, 1, 0, 1, 0],
[0, 1, 0, 0, 0, 0],
[0, 1, 0, 0, 0, 1],
[0, 0, 0, 0, 0, 1, 0, 1, 0],
[0, 0, 0, 0, 1, 0, 0, 0, 1],
[0, 0, 1, 0, 0, 0, 0, 1, 0],
[0, 0, 1, 0, 1, 0, 0, 0, 0],
[0, 1, 0, 0, 0, 0, 0, 0, 1],
[0, 1, 0, 0, 0, 1, 0, 0, 0]]

Related

How do I create a list of all combinations, given a population and subset? (nCr)

I am trying to get a List of Lists for all of the combinations with a given Population and a given SubSet.
For this example, say there's a population of 12, and a subset of 3. From the Combinations Formula (nCr) I know there should be 220 combinations. How do I get a list of all of the 220 possible combinations?
Example Result:
[[1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0],
etc.,
etc.,
[0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1]]
You can generate all possible combinations of the 3 indices where you have ones, and build each output accordingly:
from itertools import combinations
def combs(n, r):
for comb in combinations(range(n), r):
yield [1 if i in comb else 0 for i in range(n)]
Sample run with your values:
c = list(combs(12, 3))
print(len(c))
# 220
We have the expected number of combinations, see the first ones:
print(c[:5])
# [[1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0],
# [1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0],
# [1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0],
# [1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0],
# [1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0]]

How to expand a 2d array based on a number

I want that:
num = 3
array = [0,0,0,0,0]
become this:
array = ([0,0,0,0,0],[0,0,0,0,0],[0,0,0,0,0])
I've tried this:
array = ([0,0,0,0,0],)*num
and this:
array = [[0,0,0,0,0]]*num
but when I set the values, it sets it everywhere.
num = 3
array = [[0,0,0,0,0]]*num
print(array)
array[0][0] = 1
array[1][1] = 2
print(array)
[[0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0]]
[[1, 2, 0, 0, 0], [1, 2, 0, 0, 0], [1, 2, 0, 0, 0]]
when it should be that:
[[0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0]]
[[1, 0, 0, 0, 0], [0, 2, 0, 0, 0], [0, 0, 0, 0, 0]]
Use List Comprehensions to build the 2D list . The thing that you are doing is actually making 3(num) references to the same list !! To understand it much better, consider this example
>>> a=b=[5]
>>> a[0] = 6
>>> a
[6]
>>> b
[6]
So use list comprehensions, so that all the inner lists are "unique".
num = 3
array = [[0,0,0,0,0] for i in range(num)]
print(array)
array[0][0] = 1
array[1][1] = 2
print(array)
Output:
[[0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0]]
[[1, 0, 0, 0, 0], [0, 2, 0, 0, 0], [0, 0, 0, 0, 0]]

How can I manipulate a list of lists?

How can i iterate through a list of lists so as to make any of the lists with a "1" have the top(0), top left(0), top right(0), bottom(0), bottom right(0),bottom left(0) also become a "1" as shown below? making list 1 become list 2
list_1 =[[0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0],
[0,0,0,1,0,0,0,0],
[0,0,0,0,0,0,0,0]]
list_2 =[[0,0,0,0,0,0,0,0],
[0,0,1,1,1,0,0,0],
[0,0,1,1,1,0,0,0],
[0,0,1,1,1,0,0,0]]
This is a common operation known as "dilation" in image processing. Your problem is 2-dimensional, so you would be best served using
a more appropriate 2-d data structure than a list of lists, and
an already available library function, rather than reinvent the wheel
Here is an example using a numpy ndarray and scipy's binary_dilation respectively:
>>> import numpy as np
>>> from scipy import ndimage
>>> a = np.array([[0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0],
[0,0,0,1,0,0,0,0],
[0,0,0,0,0,0,0,0]], dtype=int)
>>> ndimage.binary_dilation(a, structure=ndimage.generate_binary_structure(2, 2)).astype(a.dtype)
array([[0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 1, 1, 1, 0, 0, 0],
[0, 0, 1, 1, 1, 0, 0, 0],
[0, 0, 1, 1, 1, 0, 0, 0]])
With numpy, which is more suitable to manipulate 2D list in general. If you're doing image analysis, see #wim answer. Otherwise here is how you could manage it with numpy only.
> import numpy as np
> list_1 =[[0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0],
[0,0,0,1,0,0,0,0],
[0,0,0,0,0,0,0,0]]
> l = np.array(list_1) # convert the list into a numpy array
> pos = np.where(l==1) # get the position where the array is equal to one
> pos
(array([2]), array([3]))
# make a lambda function to limit the lower indexes:
get_low = lambda x: x-1 if x>0 else x
# get_high is not needed.
# slice the array around that position and set the value to one
> l[get_low(pos[0]):pos[0]+2,
get_low(pos[1]):pos[1]+2] = 1
> l
array([[0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 1, 1, 1, 0, 0, 0],
[0, 0, 1, 1, 1, 0, 0, 0],
[0, 0, 1, 1, 1, 0, 0, 0]])
> corner
array([[0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 1]])
> p = np.where(corner==1)
> corner[get_low(p[0]):p[0]+2,
get_low(p[1]):p[1]+2] = 1
> corner
array([[0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 1, 1],
[0, 0, 0, 0, 0, 0, 1, 1]])
HTH

Generating all possible combinations of a zeros and b ones

Is there an efficient way to generate a list (or an array) of all possible combinations of say 2 ones and 8 zeros? E.g.
[[0,0,0,0,0,0,0,0,1,1],
[0,0,0,0,0,0,0,1,0,1,],
...]
This works, but there could be a better way?
import numpy as np
result = []
for subset in itertools.combinations(range(10), 2):
subset = list(subset)
c = np.zeros(10)
c[subset] = 1
result.append(c)
Would love to have some ideas on how to optimize this code.
Well, it's not much different but doing bulk operations on Numpy arrays is bound to have much less overhead:
import itertools
import numpy
which = numpy.array(list(itertools.combinations(range(10), 2)))
grid = numpy.zeros((len(which), 10), dtype="int8")
# Magic
grid[numpy.arange(len(which))[None].T, which] = 1
grid
#>>> array([[1, 1, 0, 0, 0, 0, 0, 0, 0, 0],
#>>> [1, 0, 1, 0, 0, 0, 0, 0, 0, 0],
#>>> [1, 0, 0, 1, 0, 0, 0, 0, 0, 0],
#>>> [1, 0, 0, 0, 1, 0, 0, 0, 0, 0],
#>>> [1, 0, 0, 0, 0, 1, 0, 0, 0, 0],
#>>> ...
The bulk of the time is then spent doing numpy.array(list(itertools.combinations(range(10), 2))). I tried using numpy.fromiter but I didn't get any speed improvements. Since half the time is literally generating the tuples, the only real way to improve further is to generate the combinations in something like C or Cython.
Alternative using numpy.bincount:
>>> [np.bincount(xs, minlength=10) for xs in itertools.combinations(range(10), 2)]
[array([1, 1, 0, 0, 0, 0, 0, 0, 0, 0], dtype=int64),
array([1, 0, 1, 0, 0, 0, 0, 0, 0, 0], dtype=int64),
array([1, 0, 0, 1, 0, 0, 0, 0, 0, 0], dtype=int64),
array([1, 0, 0, 0, 1, 0, 0, 0, 0, 0], dtype=int64),
...]
Shouldn't we be using permutations for this? Eg,
from itertools import permutations as perm
a, b = 6, 2
print '\n'.join(sorted([''.join(s) for s in set(t for t in perm(a*'0' + b*'1'))]))

How to for loop in reverse?

I'm making a water simulation program, and I need it to do a for loop through y, x. But I need it to check the most bottom y first, then up. This is my lvl:
lvl = [[0, 0, 1, 0, 0],
[0, 0, 1, 0, 0],
[0, 0, 1, 0, 0],
[0, 0, 0, 0, 0],
[0, 0, 0, 0, 0]]
I need it to check lvl[4] and then lvl[3], lvl[2], etc. Please help!
NB: I'm using nested for loops, so I can check y, x.
You can use the reversed built-in method to reverse the ordering of your list of lists:
for li in reversed(lvl):
print li
Output:
[0, 0, 0, 0, 0]
[0, 0, 0, 0, 0]
[0, 0, 1, 0, 0]
[0, 0, 1, 0, 0]
[0, 0, 1, 0, 0]
If you're using for loops, you can use range to generate a reversed sequence to index lvl with.
>>> range(4,-1,-1)
[4, 3, 2, 1, 0]
i.e., maybe something similar to:
>>> for i in range(4,-1,-1):
... print lvl[i]
...
[0, 0, 0, 0, 0]
[0, 0, 0, 0, 0]
[0, 0, 1, 0, 0]
[0, 0, 1, 0, 0]
[0, 0, 1, 0, 0]
>>>

Categories

Resources