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)]
Related
I have a list with a pair of coordinates:
e.g. coord_list = [[1,2]]
For this coordinate, I would like to append to the list coordinates that are +/- 2 points away from both the x and y coordinates. The list will contain 25 pairs of coordinates in the end, with the centre coordinate as the first element.
Any suggestions about how to go about this in Python? Thanks a lot.
The Solution
We can construct from the x and y coordinate of the point
the range of numbers of the points which are surrounding the point
by up to k = 2.
Then we build all possible combinations of these possible x and y coordinate values.
This can be neatly done with list expressions by combining two for-clauses.
Due to your desire that the original point should be placed at the beginning, we add an if [x, y] != point clause to exclude the
original point from listing by the list-expression but we add it at the beginning extra to this list-comprehension [point] + [ <list-comprehension>].
The nice thing of this solution is that you can vary k, e.g. k=3 or just one layer of cells around the original cell by setting k=1.
def vary_around(val, k=2):
return list(range(val - k, val + k + 1))
def points_around(point, k=2):
x, y = point
xs = vary_around(x, k=k)
ys = vary_around(y, k=k)
return [point] + [[x, y] for x in xs for y in ys if [x, y] != point]
Test It
You can try it:
In [39]: points_around([1, 2], k=2)
Out[39]:
[[1, 2],
[-1, 0],
[-1, 1],
[-1, 2],
[-1, 3],
[-1, 4],
[0, 0],
[0, 1],
[0, 2],
[0, 3],
[0, 4],
[1, 0],
[1, 1],
[1, 3],
[1, 4],
[2, 0],
[2, 1],
[2, 2],
[2, 3],
[2, 4],
[3, 0],
[3, 1],def points_around(point, k=2):
x, y = point
xs = vary_around(x, k=k)
ys = vary_around(y, k=k)
return {tuple(point): [[x, y] for x in xs for y in ys if [x, y] != point]}
# now, you get:
reduce(lambda dct, dct1: dct.update(dct1) and dct, [points_around(point, k=2) for point in coord_list])
[3, 2],
[3, 3],
[3, 4]]
In [40]: len(points_around([1, 2], k=2))
Out[40]: 25
With:
coord_list = [[1, 2], [3, 4]]
You apply this function again using list-comprehensions:
point_groups = [points_around(point, k=2) for point in coord_list]
Further Suggestion
Probably you want the original point at the beginning to
have it distinguished from the rest of the points.
How about using a dictionary for this purpose?
def merge_dicts(dct, dct1):
dct.update(dct1)
return dct
def points_around(point, k=2):
x, y = point
xs = vary_around(x, k=k)
ys = vary_around(y, k=k)
return {tuple(point): tuple([(x, y) for x in xs for y in ys if [x, y] != point])} # key must be a tuple and not a list
# in a dictionary so probably better to make everything a tuple
from functools import reduce
defun coords_to_points_dict(coord_list, k=2):
return reduce(merge_dicts, [points_around(point, k=k) for point in coord_list])
point2surrounding_points = coords_to_points_dict(coord_list, k=2)
point2surrounding_points
# it outputs:
{(1, 2): ((-1, 0),
(-1, 1),
(-1, 2),
(-1, 3),
(-1, 4),
(0, 0),
(0, 1),
(0, 2),
(0, 3),
(0, 4),
(1, 0),
(1, 1),
(1, 3),
(1, 4),
(2, 0),
(2, 1),
(2, 2),
(2, 3),
(2, 4),
(3, 0),
(3, 1),
(3, 2),
(3, 3),
(3, 4)),
(3, 4): ((1, 2),
(1, 3),
(1, 4),
(1, 5),
(1, 6),
(2, 2),
(2, 3),
(2, 4),
(2, 5),
(2, 6),
(3, 2),
(3, 3),
(3, 5),
(3, 6),
(4, 2),
(4, 3),
(4, 4),
(4, 5),
(4, 6),
(5, 2),
(5, 3),
(5, 4),
(5, 5),
(5, 6))}
This dictionary you can query with your points to get their surrounding points.
You could use a list comprehension to generate the 24 additional coordinates and append them to the original list:
coords = [[1,2]]
coords += [ [x+d//5-2,y+d%5-2] for x,y in coords
for d in range(25) if d != 12 ]
print(coords)
[[1, 2], [-1, 0], [-1, 1], [-1, 2], [-1, 3],
[-1, 4], [0, 0], [0, 1], [0, 2], [0, 3],
[0, 4], [1, 0], [1, 1], [1, 3], [1, 4],
[2, 0], [2, 1], [2, 2], [2, 3], [2, 4],
[3, 0], [3, 1], [3, 2], [3, 3], [3, 4]]
You could generalize it into a function for any distance like this:
def addNeighbors(coords,distance=2):
coords += [ [x+dx,y+dy] for x,y in coords
for dx in range(-distance,distance+1)
for dy in range(-distance,distance+1)
if dx or dy ]
Given a list as follows:
[(1, 2), (3, 4, 5), (6,)]
I know it's very easy to combine the list of tuples by using itertools.
(1, 3, 6), (1, 4, 6), (1, 5, 6), (2, 3, 6), (2, 4, 6), (2, 5, 6)
But how can I solve it without using itertools?
Here's a fairly generic approach with a series of loops over the input:
lst = [(1, 2), (3, 4, 5), (6,)]
result = [tuple([l]) for l in lst[0]]
for l in lst[1:]:
out = []
for r in result:
for i in range(len(l)):
out.append((*r, l[i]))
result = out
print(result)
Output:
[(1, 3, 6), (1, 4, 6), (1, 5, 6), (2, 3, 6), (2, 4, 6), (2, 5, 6)]
[(x, y, 6) for x in (1, 2) for y in (3, 4, 5)]
Also see Get the cartesian product of a series of lists? for more general solutions
def product(pools):
result = [[]]
for pool in pools:
result = [x+[y] for x in result for y in pool]
return result
product([(1,2,3),(4,5),(6,)])
[[1, 4, 6], [1, 5, 6], [2, 4, 6], [2, 5, 6], [3, 4, 6], [3, 5, 6]]
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.
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.
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)]