This question already has answers here:
How to get the cartesian product of multiple lists
(17 answers)
Closed 8 years ago.
I have the following lists:
[1,2,3]
[1]
[1,2,3,4]
From the above, I would like to generate a list containing:
[[1,1,1],[1,1,2],[1,1,3],[1,1,4],
[2,1,1], [2,1,2], [2,1,3], [2,1,4],
[3,1,2], [3,1,3],[3,1,4]]
What is this process called?
Generate a factorial of python lists?
Is there a built-in library that does this?
Using itertools.product:
>>> import itertools
>>> [list(xs) for xs in itertools.product([1,2,3], [1], [1,2,3,4])]
[[1, 1, 1], [1, 1, 2], [1, 1, 3], [1, 1, 4], [2, 1, 1], [2, 1, 2], [2, 1, 3], [2, 1, 4], [3, 1, 1], [3, 1, 2], [3, 1, 3], [3, 1, 4]]
itertools.product
>>> lists = [[1,2,3], [1], [1,2,3,4]]
>>> from itertools import product
>>> map(list, product(*lists))
[[1, 1, 1], [1, 1, 2], [1, 1, 3], [1, 1, 4], [2, 1, 1], [2, 1, 2], [2, 1, 3], [2, 1, 4], [3, 1, 1], [3, 1, 2], [3, 1, 3], [3, 1, 4]]
Note: the usage of map allows me to convert the otherwise tuple results of product's iteration into lists easily.
inputList = [[1,2,3], [1], [1,2,3,4]]
import itertools
print [list(item) for item in itertools.product(*inputList)]
Output
[[1, 1, 1],
[1, 1, 2],
[1, 1, 3],
[1, 1, 4],
[2, 1, 1],
[2, 1, 2],
[2, 1, 3],
[2, 1, 4],
[3, 1, 1],
[3, 1, 2],
[3, 1, 3],
[3, 1, 4]]
As suggested in the other answers itertools.product is the way to go here, but for completeness and as an illustration of what itertools.product does here is a solution using a list comprehension:
result = [[x,y,z] for x in [1,2,3] for y in [1] for z in [1,2,3,4]]
Here is the same thing using normal for loops which may make it a bit more readable:
result = []
for x in [1,2,3]:
for y in [1]:
for z in [1,2,3,4]:
result.append([x, y, z])
Related
This is what i have-
def merge_list(mylist)
list1 = []
one_len = len(mylist)
two_len = len(mylist[0][0])
for index in range(two_len):
combine_list = []
for index2 in range(one_len):
combine_list.extend([a[index] for a in mylist[
index2]])
list1.append(combine_list)
return list1
But i have a problem with the output-
for example:
input-
mylist=[[[1, 1, 1], [1, 1, 1], [1, 1, 1], [1, 1, 1]], [[2, 2, 2], [2, 2, 2], [2, 2, 2], [2, 2, 2]], [[3, 3, 3], [3, 3, 3], [3, 3, 3], [3, 3, 3]]]
in short-
[[[1]*3]*4, [[2]*3]*4, [[3]*3]*4]
the output is -
[[[1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3], [1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3], [1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3]]]
and not -
[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]
in short-
[[[1, 2, 3]]*3]*4
I would be happy to solve the problem and advise how to shorten the code.
In order to fix your code, you just need to update the return statement like this:
return [list1]
Though there is still a hidden problem when your inner lists lengths are longer than one element. Check your outputs with sample inputs like [[[2,1], [3,1]]].
One further - more compact - solution may be obtained by concatenating the inner lists within a cycle, then recreate the number of dimensions you need, moving the complexity from O(n^2) to O(n).
mylist = [[[2,1]],[[3,1]]]
def merge_list(mylist):
l_out = []
for l in mylist:
l_out += l[0]
return [[l_out]]
EDIT: In case of more complex inputs, you can extract first all elements and eventually fix the dimensions. This will still bring O(n^2) complexity though:
def merge_list(lst):
elements = [[] for _ in range(len(mylist[0]))]
for l1 in mylist:
for idx, l2 in enumerate(l1):
elements[idx] += l2
return [elements]
merge_list(mylist)
Input:
[[[1], [1]], [[2], [2]], [[3], [3]]]
Output:
[[[1, 2, 3], [1, 2, 3]]]
Say I have a list inside a list, that is contained inside a list. For example:
foo = [[[2, 2, 2], [1, 1, 1], [3, 3, 3]], [[2, 2, 2], [1, 1, 1], [3, 3, 3]]]
And I wanted to sort it in order:
foo = [[[1, 1, 1], [2, 2, 2], [3, 3, 3]], [[1, 1, 1], [2, 2, 2], [3, 3, 3]]]
I could use [sorted(i) for i in foo] to achieve this. However is there some way to sort this list without list comprehension (or creating a new list)?
The values inside the lists themselves will change but do not need to be sorted.
Everything I have tried just boils down to the same method as above.
If you want to avoid creating a new list, then just iterate over the lists and call .sort()
>>> foo = [[[2, 2, 2], [1, 1, 1], [3, 3, 3]], [[2, 2, 2], [1, 1, 1], [3, 3, 3]]]
for i in foo:
i.sort()
>>> foo
[[[1, 1, 1], [2, 2, 2], [3, 3, 3]], [[1, 1, 1], [2, 2, 2], [3, 3, 3]]]
If you don't mind creating a new list, how about using map function:
In [1]: foo = [[[2, 2, 2], [1, 1, 1], [3, 3, 3]], [[2, 2, 2], [1, 1, 1], [3, 3, 3]]]
In [2]: list(map(sorted, foo))
Out[2]: [[[1, 1, 1], [2, 2, 2], [3, 3, 3]], [[1, 1, 1], [2, 2, 2], [3, 3, 3]]]
This question already has an answer here:
Name is not defined in a list comprehension with multiple loops
(1 answer)
Closed 1 year ago.
I've referenced this question How to generate all permutations of a list in Python, where I faced a similar scenario that expressed in this question.
This time, I wanna generate all possible permutations(without an empty list [])of a list , and store it in another single list. E.g. the target list is a_list=[1, 2, 3], and I want something like:
[
[1], [2], [3],
[1, 2], [1, 3], [2, 1], [2, 3], [3, 1], [3, 2],
[1, 2, 3], [1, 3, 2], [2, 1, 3], [2, 3, 1], [3, 1, 2], [3, 2, 1]
]
I've tried this code, which worked successfully (using built-in itertools module):
import itertools
perm = list()
for i in range(1, len(a_list) + 1):
perm.extend([list(x) for x in itertools.permutations(a_list, i)])
I wanna to try it in a list comprehension way, but I failed with this attempt:
perm = [list(x) for x in permutations(a_list, i) for i in range(1, len(a_list)+1)]
So is there any feasible list comprehension method to do this stuff?
As the comments say, you have mixed up the order of the for loops. The first for is the outer loop, the second for is the inner loop (read left to right in a list comprehension).
This is the correct ordering:
import itertools
a_list=[1, 2, 3]
perm = [list(x) for i in range(1, len(a_list)+1) for x in itertools.permutations(a_list, i)]
print(perm)
>>>[[1], [2], [3],
[1, 2], [1, 3], [2, 1], [2, 3], [3, 1], [3, 2],
[1, 2, 3], [1, 3, 2], [2, 1, 3], [2, 3, 1], [3, 1, 2], [3, 2, 1]]
This question already has answers here:
List of lists changes reflected across sublists unexpectedly
(17 answers)
Closed 4 years ago.
Here is a snippet of python code:
a = [[0]*3]*4
for i in range(4):
for j in range(3):
a[i][j] = i+j
print(a[i][j])
print(a)
However, the outputs of the two prints are different.
The former one prints what I want. And the second prints all the same for the 4 sublists.
It seems the problem of shallow copying. I really don't understand how and why it happens.
Update:
After I have solved this, I found another problem:
a = [[0]*3]*4
for i in range(4):
a[i] = [i, 2*i, 3*i]
The result is also what I want. I'm once again confused about this.
Who can tell me the difference?
a = [[0]*3]*4
for i in range(4):
for j in range(3):
a[i][j] = i+j
print(a)
print(a[i][j])//show the execution at every step
print(a)
At each step the list with same column is updated with the same value.
output is
[[0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0]]
0
[[0, 1, 0], [0, 1, 0], [0, 1, 0], [0, 1, 0]]
1
[[0, 1, 2], [0, 1, 2], [0, 1, 2], [0, 1, 2]]
2
[[1, 1, 2], [1, 1, 2], [1, 1, 2], [1, 1, 2]]
1
[[1, 2, 2], [1, 2, 2], [1, 2, 2], [1, 2, 2]]
2
[[1, 2, 3], [1, 2, 3], [1, 2, 3], [1, 2, 3]]
3
[[2, 2, 3], [2, 2, 3], [2, 2, 3], [2, 2, 3]]
2
[[2, 3, 3], [2, 3, 3], [2, 3, 3], [2, 3, 3]]
3
[[2, 3, 4], [2, 3, 4], [2, 3, 4], [2, 3, 4]]
4
[[3, 3, 4], [3, 3, 4], [3, 3, 4], [3, 3, 4]]
3
[[3, 4, 4], [3, 4, 4], [3, 4, 4], [3, 4, 4]]
4
[[3, 4, 5], [3, 4, 5], [3, 4, 5], [3, 4, 5]]
5
[[3, 4, 5], [3, 4, 5], [3, 4, 5], [3, 4, 5]]
The multiplier of operator taking a list and an int will make makes shallow copies of the elements of the list, so you're on the right track.
Initialise like this instead
a = [[0] * 3 for _ in range(4)]
I have this nested list:
nested = [[1, 1, 1], [2, 2, 2], [3, 3, 3]]
I wanted to subtract 1 from the first 2 elements of the inner list so I tried it with list comprehension:
nested = [[x - 1 for x in stack[0:2]] for stack in nested]
It did give me back the first 2 elements subtracted by 1 for the inner lists but it removed the last element completely
nested = [[0, 0], [1, 1], [2, 2]]
I thought that by slicing the list, it will not affect the other element. However in this case it didn't work. Can someone explain this to me?
To keep the 3rd element, include it in the list comprehension:
>>> [ [x - 1 for x in stack[0:2]] + stack[2:] for stack in nested ]
[[0, 0, 1], [1, 1, 2], [2, 2, 3]]
The above works for stack of any length.
Or, if stack always has exactly three elements:
>>> [[x-1, y-1, z] for x, y, z in nested]
[[0, 0, 1], [1, 1, 2], [2, 2, 3]]
Or, you can make the changes in place:
>>> for stack in nested: stack[0]-=1; stack[1]-=1
...
>>> nested
[[0, 0, 1], [1, 1, 2], [2, 2, 3]]
Another option is to use numpy which does this sort of slicing naturally
import numpy as np
nested = np.array([[1, 1, 1], [2, 2, 2], [3, 3, 3]])
nested[:,:2] -= 1
returns
array([[0, 0, 1],
[1, 1, 2],
[2, 2, 3]])
Try it like this:
nested = [[x - 1 if i < 2 else x for i,x in enumerate(stack)] for stack in nested]
This will affect only first two elements keeping the rest as is.
You can use enumerate:
nested = [[1, 1, 1], [2, 2, 2], [3, 3, 3]]
new_nested = [[a-1 if i == 0 or i == 1 else a for i, a in enumerate(b)] for b in nested]
Output:
[[0, 0, 1], [1, 1, 2], [2, 2, 3]]
Edit: alternative, with map:
nested = [[1, 1, 1], [2, 2, 2], [3, 3, 3]]
new_nested = [map(lambda x:x-1, i[:2])+[i[-1]] for i in nested]
Output:
[[0, 0, 1], [1, 1, 2], [2, 2, 3]]