I am able to produce all combinations given a particular value (k) for a single list as follows:
lst = []
p = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
c = itertools.combinations(p, k)
for i in c:
lst.append(list(i))
print lst
Note, in this code, k requires a specific value to be inputted - it cannot be a variable.
However, I now have multiple lists in which I need all combinations for various k:
m = [1, 2, 3, 4]
t = [1, 2, 3, 4]
c = [1, 2, 3, 4, 5]
ss =[1, 2, 3]
Put simply: I require an output of all the combinations possible for all these lists. E.g. k = 1 through 4 for m and t, 1 through 5 for c, and 1 through 3 for ss.
Example of k = 2 for ss would be
m = [1, 2, 3, 4]
t = [1, 2, 3, 4]
c = [1, 2, 3, 4, 5]
ss = [1, 2]
m = [1, 2, 3, 4]
t = [1, 2, 3, 4]
c = [1, 2, 3, 4, 5]
ss = [1, 3]
m = [1, 2, 3, 4]
t = [1, 2, 3, 4]
c = [1, 2, 3, 4, 5]
ss = [2, 3]
Follow this pattern for all values combinations of k possible in all variables.
Let me know if this is unclear and I can edit question accordingly.
You can get your output via itertools.product alone or via combinations. We could cram this all into one line if we really wanted, but I think it's more comprehensible to write
from itertools import combinations, product
def all_subs(seq):
for i in range(1, len(seq)+1):
for c in combinations(seq, i):
yield c
after which we have
>>> m,t,c,ss = [1,2,3,4],[1,2,3,4],[1,2,3,4,5],[1,2,3]
>>> seqs = m,t,c,ss
>>> out = list(product(*map(all_subs, seqs)))
>>> len(out)
48825
which is the right number of results:
>>> (2**4 - 1) * (2**4 - 1) * (2**5-1) * (2**3 - 1)
48825
and hits every possibility:
>>> import pprint
>>> pprint.pprint(out[:4])
[((1,), (1,), (1,), (1,)),
((1,), (1,), (1,), (2,)),
((1,), (1,), (1,), (3,)),
((1,), (1,), (1,), (1, 2))]
>>> pprint.pprint(out[-4:])
[((1, 2, 3, 4), (1, 2, 3, 4), (1, 2, 3, 4, 5), (1, 2)),
((1, 2, 3, 4), (1, 2, 3, 4), (1, 2, 3, 4, 5), (1, 3)),
((1, 2, 3, 4), (1, 2, 3, 4), (1, 2, 3, 4, 5), (2, 3)),
((1, 2, 3, 4), (1, 2, 3, 4), (1, 2, 3, 4, 5), (1, 2, 3))]
Related
a = [1, 2, 3, 4]
Combinations are:
[1, 2, 3], [1, 2, 4], [1, 3, 4], [2, 3, 4]
[2, 3], [2, 4], [3, 4], [1, 3], [1, 4], [1, 2]
[1], [2], [3], [4]
Code:
from itertools import combinations
a = [1, 2, 3, 4]
list1 = list()
b = combinations(a, len(a)-1)
for i in b:
list1.append(list(i))
list2 = list()
while len(list1) != 0:
temp = list1.pop()
comb = combinations(temp, len(temp)-1)
for i in comb:
if list(i) not in list2:
print(list(i))
list2.append(list(i))
You're correct about using itertools.combinations, but you need to loop through several possible lengths to produce your final output. Finally, I used itertools.chain.from_iterable to flatten the resulting list:
>>> from itertools import chain, combinations
>>> list(chain.from_iterable(combinations(a, i) for i in range(1, len(a))))
[(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)]
If you are dead set on the elements being lists, store the result, and use map
list(map(list, res))
How do I convert a list
[1, 2, 3, 4, 5]
to list of tuple
[(1, 2, 3, 4, 5)]
And
convert a tuple
(1, 2, 3, 4, 5)
to list of tuple
[(1, 2, 3, 4, 5)]
from list:
[tuple(x)]
from tuple:
[x]
i.e.
>>> x = [1,2,3]
>>> [tuple(x)]
[(1, 2, 3)]
>>> x = (1, 2, 3)
>>> [x]
[(1, 2, 3)]
arr = [1, 2, 3, 4]
print(arr)
tpl = (arr,)
print(type(tpl), tpl)
output:
[1, 2, 3, 4]
<class 'tuple'> ([1, 2, 3, 4],)
case 2:
tpl_2 = (1, 2, 3, 4)
print(tpl_2)
arr_2 = [tpl_2]
print(type(arr_2), arr_2)
output:
(1, 2, 3, 4)
<class 'list'> [(1, 2, 3, 4)]
What about doing the following:-
your_list = [1,2,3,4]
new_list = [tuple(your_list)]
And in the second case:-
your_tuple = (1,2,3,4)
new_list = [your_tuple]
try it !
l=[1, 2, 3, 4, 5]
t=tuple(i for i in l)
t
output:
(1, 2, 3, 4, 5)
and
tl = [t]
tl
output:
[(1, 2, 3, 4, 5)]
Say a list a = [4, 8, 5, 7, 7, 7, 7, 3, 2, 2, 2, 5, 3, 3, 3, 3, 3] is there a way to create this list with list comprehension?
a = [4, 8, 5, (4 times 7), 3, (3 times 2), 5, (5 times 3)]
I know how to do it with just one repeated value, but not three and non-repeated values in between.
If you are trying to create a literal list from hard-coded counts, then this is far easier achieved by concatenation:
a = [4, 8, 5] + 4 * [7] + [3] + 3 * [2] + [5] + 5 * [3]
If you must use a list comprehension, you'll have to include a multiplier for each of the values, then use a double loop to repeat the values:
# list of (count, value) pairs
inputs = [(1, 4), (1, 8), (1, 5), (4, 7), (1, 3), (3, 2), (1, 5), (5, 3)]
a = [i for count, i in inputs for _ in range(count)]
Demo:
>>> [4, 8, 5] + 4 * [7] + [3] + 3 * [2] + [5] + 5 * [3]
[4, 8, 5, 7, 7, 7, 7, 3, 2, 2, 2, 5, 3, 3, 3, 3, 3]
>>> inputs = [(1, 4), (1, 8), (1, 5), (4, 7), (1, 3), (3, 2), (1, 5), (5, 3)]
>>> [i for count, i in inputs for _ in range(count)]
[4, 8, 5, 7, 7, 7, 7, 3, 2, 2, 2, 5, 3, 3, 3, 3, 3]
How to generate something like
[(), (1,), (1,2), (1,2,3)..., (1,2,3,...n)]
and
[(), (4,), (4,5), (4,5,6)..., (4,5,6,...m)]
then take the product of them and merge into
[(), (1,), (1,4), (1,4,5), (1,4,5,6), (1,2), (1,2,4)....(1,2,3,...n,4,5,6,...m)]
?
For the first two lists I've tried the powerset recipe in https://docs.python.org/2/library/itertools.html#recipes , but there will be something I don't want, like (1,3), (2,3)
For the product I've tested with chain and product, but I just can't merge the combinations of tuples into one.
Any idea how to do this nice and clean? Thanks!
Please note that, single element tuples are denoted like this (1,).
a = [(), (1,), (1, 2), (1, 2, 3)]
b = [(), (4,), (4, 5), (4, 5, 6)]
from itertools import product
for item1, item2 in product(a, b):
print item1 + item2
Output
()
(4,)
(4, 5)
(4, 5, 6)
(1,)
(1, 4)
(1, 4, 5)
(1, 4, 5, 6)
(1, 2)
(1, 2, 4)
(1, 2, 4, 5)
(1, 2, 4, 5, 6)
(1, 2, 3)
(1, 2, 3, 4)
(1, 2, 3, 4, 5)
(1, 2, 3, 4, 5, 6)
If you want them in a list, you can use list comprehension like this
from itertools import product
print [sum(items, ()) for items in product(a, b)]
Or even simpler,
print [items[0] + items[1] for items in product(a, b)]
You can try like this,
>>> a=[(), (1,), (1,2), (1,2,3)]
>>> b=[(), (4,), (4,5), (4,5,6)]
>>> for ix in a:
... for iy in b:
... print ix + iy
...
()
(4,)
(4, 5)
(4, 5, 6)
(1,)
(1, 4)
(1, 4, 5)
(1, 4, 5, 6)
(1, 2)
(1, 2, 4)
(1, 2, 4, 5)
(1, 2, 4, 5, 6)
(1, 2, 3)
(1, 2, 3, 4)
(1, 2, 3, 4, 5)
(1, 2, 3, 4, 5, 6)
If you don't want to use any special imports:
start = 1; limit = 10
[ range(start, start + x) for x in range(limit) ]
With start = 1 the output is:
[[], [1], [1, 2], [1, 2, 3], [1, 2, 3, 4], [1, 2, 3, 4, 5], [1, 2, 3, 4, 5, 6], [1, 2, 3, 4, 5, 6, 7], [1, 2, 3, 4, 5, 6, 7, 8], [1, 2, 3, 4, 5, 6, 7, 8, 9]]
If you want to take the product, maybe using itertools might be most elegant.
Let's say that I have two arrays in the form
a = [0, 0, 1, 1, 2, 3, 3, 3, 4, 4, 5, 6]
b = [1, 2, 1, 2, 1, 4, 7, 9, 4, 8, 1, 1]
As you can see, the above arrays are sorted, when considered a and b as columns of a super array.
Now, I want to do a searchsorted on this array. For instance, if I search for (3, 7) (a = 3 and b = 7), I should get 6.
Whenever there are duplicate values in a, the search should continue with values in b.
Is there a built-in numpy method to do it? Or what could be the efficient way to do it, assuming that I have million entries in my array.
I tried with numpy.recarray, to create one recarray with a and b and tried searching in it, but I am getting the following error.
TypeError: expected a readable buffer object
Any help is much appreciated.
You're almost there. It's just that numpy.record (which is what I assume you used, given the error message you received) isn't really what you want; just create a one-item record array:
>>> a_b = numpy.rec.fromarrays((a, b))
>>> a_b
rec.array([(0, 1), (0, 2), (1, 1), (1, 2), (2, 1), (3, 4), (3, 7), (3, 9),
(4, 4), (4, 8), (5, 1), (6, 1)],
dtype=[('f0', '<i8'), ('f1', '<i8')])
>>> numpy.searchsorted(a_b, numpy.array((3, 7), dtype=a_b.dtype))
6
It might also be useful to know that sort and argsort sort record arrays lexically, and there is also lexsort. An example using lexsort:
>>> random_idx = numpy.random.permutation(range(12))
>>> a = numpy.array(a)[random_idx]
>>> b = numpy.array(b)[random_idx]
>>> sorted_idx = numpy.lexsort((b, a))
>>> a[sorted_idx]
array([0, 0, 1, 1, 2, 3, 3, 3, 4, 4, 5, 6])
>>> b[sorted_idx]
array([1, 2, 1, 2, 1, 4, 7, 9, 4, 8, 1, 1])
Sorting record arrays:
>>> a_b = numpy.rec.fromarrays((a, b))
>>> a_b[a_b.argsort()]
rec.array([(0, 1), (0, 2), (1, 1), (1, 2), (2, 1), (3, 4), (3, 7), (3, 9),
(4, 4), (4, 8), (5, 1), (6, 1)],
dtype=[('f0', '<i8'), ('f1', '<i8')])
>>> a_b.sort()
>>> a_b
rec.array([(0, 1), (0, 2), (1, 1), (1, 2), (2, 1), (3, 4), (3, 7), (3, 9),
(4, 4), (4, 8), (5, 1), (6, 1)],
dtype=[('f0', '<i8'), ('f1', '<i8')])
You could use a repeated searchsorted from left and right:
left, right = np.searchsorted(a, 3, side='left'), np.searchsorted(a, 3, side='right')
index = left + np.searchsorted(b[left:right], 7)
This works for me:
>>> a = [0, 0, 1, 1, 2, 3, 3, 3, 4, 4, 5, 6]
>>> b = [1, 2, 1, 2, 1, 4, 7, 9, 4, 8, 1, 1]
>>> Z = numpy.array(zip(a, b), dtype=[('a','int'), ('b','int')])
>>> Z.searchsorted(numpy.asarray((3,7), dtype=Z.dtype))
6
I think the trick might be to make sure the argument to searchsorted has the same dtype as the array. When I try Z.searchsorted((3, 7)) I get a segfault.
Here's an interesting way to do it (though it's not the most efficient way, as I believe it's O(n) rather than O(log(n)) as ecatmur's answer would be; it is, however, more compact):
np.searchsorted(a + 1j*b, a_val + 1j*b_val)
Example:
>>> a = np.array([0, 0, 1, 1, 2, 3, 3, 3, 4, 4, 5, 6])
>>> b = np.array([1, 2, 1, 2, 1, 4, 7, 9, 4, 8, 1, 1])
>>> np.searchsorted(a + 1j*b, 4 + 1j*8)
9
n arrays extension :
import numpy as np
def searchsorted_multi(*args):
v = args[-1]
if len(v) != len(args[:-1]):
raise ValueError
l, r = 0, len(args[0])
ind = 0
for vi, ai in zip(v, args[:-1]):
l, r = [np.searchsorted(ai[l:r], vi, side) for side in ('left', 'right')]
ind += l
return ind
if __name__ == "__main__":
a = [0, 0, 1, 1, 2, 3, 3, 3, 4, 4, 5, 6]
b = [1, 2, 1, 2, 1, 4, 7, 9, 4, 8, 1, 1]
c = [1, 2, 1, 2, 1, 4, 7, 9, 4, 8, 1, 2]
assert(searchsorted_multi(a, b, (3, 7)) == 6)
assert(searchsorted_multi(a, b, (3, 0)) == 5)
assert(searchsorted_multi(a, b, c, (6, 1, 2)) == 12)
Or without numpy:
>>> import bisect
>>> a = [0, 0, 1, 1, 2, 3, 3, 3, 4, 4, 5, 6]
>>> b = [1, 2, 1, 2, 1, 4, 7, 9, 4, 8, 1, 1]
>>> bisect.bisect_left(zip(a,b), (3,7))
6