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]]
Related
I need help to get a list from an other :
input :
[[1, 1], [1, 1], [2, 2], [1, 1], [1, 1], [2, 2], [3, 3], [4, 4]]
output wanted :
[0, 0, 1, 0, 0, 1, 2, 3]
I tried to use enumerate but I fail, any suggestion ?
Edit : Every time I meet a new element in the list, I associate this new element with a number (start from 0 and +1 every new element) and if I recognize it later I put the same number, so [1,1] --> 0 because is the first element we met and [2,2] --> 1 etc...
Okay I found a solution :
One more thing before, my example is bad because I can have [1,2] in element of the list for input
the solution I found is
line = [[1, 1], [1, 1], [2, 2], [1, 1], [2, 1], [2, 2], [3, 3], [4, 4]]
p = []
line_not = []
k = 0
for i in range (len(line)):
if line[i] in line[:i]:
p.append(line_not[:k].index(line[i]))
else:
p.append(k)
line_not.append(line[i])
k+=1
the output is :
[0, 0, 1, 0, 2, 1, 3, 4]
If u have a better solution, tell me !
try to make a map, this works:
inp=[[1, 1], [1, 1], [2, 2], [1, 1], [1, 1], [2, 2], [3, 3], [4, 4]]
out = [0, 0, 1, 0, 0, 1, 2, 3]
mymap={inp[0][0]:0}
output = [0]
k_count=1
for i in inp[1:]:
if i[0] in mymap.keys():
output.append(mymap[i[0]])
else:
mymap[i[0]] = k_count
output.append(mymap[i[0]])
k_count+=1
and then output == [0, 0, 1, 0, 0, 1, 2, 3]
First build a dictionary that does the assocation of each unique element with a number:
>>> x = [[1, 1], [1, 1], [2, 2], [1, 1], [1, 1], [2, 2], [3, 3], [4, 4]]
>>> d = {}
>>> for [i, _] in x:
... if i not in d:
... d[i] = len(d)
...
and then you can easily build your output list by doing lookups in that dictionary:
>>> [d[i] for [i, _] in x]
[0, 0, 1, 0, 0, 1, 2, 3]
this would work in your current example, but it is not a comprehensive solution. Without context its hard to understand what you are trying to achieve, so use with care:
import numpy as np
inp = [[1, 1], [1, 1], [2, 2], [1, 1], [1, 1], [2, 2], [3, 3], [4, 4]]
out = np.array([i[0] for i in inp]) - 1
print(out) # result: [0 0 1 0 0 1 2 3]
Hi I'm trying to make a list of all possible cohesive combinations of another list, so from [0, 1, 2, 3] I'd like to get [[0], [0, 1], [0, 1, 2], [0, 1, 2, 3], [1], [1, 2], [1, 2, 3], [2], [2, 3], [3]]. So far I've got this:
def expandArray(arr):
result = []
for x in range(0, len(arr)):
subArray = [arr[x]]
result.append(subArray)
for y in range(x + 1, len(arr)):
subArray.append(arr[y])
result.append(subArray)
return(result)
But this returns: [[0, 1, 2, 3], [0, 1, 2, 3], [0, 1, 2, 3], [0, 1, 2, 3], [1, 2, 3], [1, 2, 3], [1, 2, 3], [2, 3], [2, 3], [3]].
What am I doing wrong ?
subArray is a list that you modify in your for loop. When you append to it, you do not create a new list, but you modify it, and then put it in the list again, so will in the end get a result with several copies of the same list. Compare this code:
a = []
b = [5]
a.append(b)
b.append(1)
a.append(b)
print(a)
would output:
[[5, 1], [5, 1]]
Here is a way to have your desired output using list slicing:
def get_combs(iterable):
for k, _ in enumerate(iterable):
elm = k
while elm <= len(iterable):
data = iterable[k:elm]
elm += 1
if data:
yield data
combs = list(get_combs([0, 1, 2, 3]))
print(combs)
Output:
[[0], [0, 1], [0, 1, 2], [0, 1, 2, 3], [1], [1, 2], [1, 2, 3], [2], [2, 3], [3]]
I have two lists of lists of the same length in Python 3 as follows:
A = [[0], [0, 1], [0, 1, 2], [0, 1], [0, 1, 2, 3]]
W = [[2, 2], [1, 2, 3], [2, 2, 2, 3], [1, 3, 4, 4], [1, 1, 3, 4]]
Elements of A are indices of elements of W. I would like to remove the elements of W given A. So, in the example, I would like to remove W[0][0], W[1][0], W[1][1], W[2][0], W[2][1], W[2][2], etc.
What I did is this:
for t in range(len(A)):
del W[t][A[t]]
But this gives the following error: TypeError: list indices must be integers or slices, not list
Unlike numpy arrays, you cannot index a list with a list. But you can use a list comprehension for this task:
A = [[0], [0, 1], [0, 1, 2], [0, 1], [0, 1, 2, 3]]
W = [[2, 2], [1, 2, 3], [2, 2, 2, 3], [1, 3, 4, 4], [1, 1, 3, 4]]
res = [[j for i, j in enumerate(w) if i not in a] for a, w in zip(A, W)]
print(res)
[[2], [3], [3], [4, 4], []]
Or, if you are happy using a 3rd party library, numpy syntax is simpler:
import numpy as np
res = [np.delete(i, j).tolist() for i, j in zip(W, A)]
One easy way is to use two nested loops. As you have probably noticed by now, you need two index numbers - one for the list in A and another for the element number of this list. Here is one way to tackle the problem:
A = [[0], [0, 1], [0, 1, 2], [0, 1], [0, 1, 2, 3]]
W = [[2, 2], [1, 2, 3], [2, 2, 2, 3], [1, 3, 4, 4], [1, 1, 3, 4]]
#cycle through list A and keep track of the list number i
for i, a_list in enumerate(A):
#retrieve index from each list in A, start with the highest index to avoid index problems
for j in sorted(a_list, reverse = True):
#delete the element j in list i of W
del W[i][j]
print(W)
#output
#[[2], [3], [3], [4, 4], []]
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])
Say I have a list:
[[0, 0], [0, 1], [1, 0], [0, 2], [1, 1], [2, 0], [0, 3], [1, 2], [2, 1], [3, 0]]
And I've produced another list from the one above, on the basis of some elements meeting a condition, lets say having a value equal to three:
[[0, 3], [3, 0]]
But now I want to access some elements from the bigger list, on the basis of some modification to my second list, lets say subtracting two from only those values equal to three in the second list. So I want to access those values in the first list taking the values [0,1] and [1,0] for the case of my second list here.
How do I proceed?
Something like this:
>>> lis = [[0, 0], [0, 1], [1, 0], [0, 2], [1, 1], [2, 0], [0, 3], [1, 2], [2, 1], [3, 0]]
>>> lis1 = [[0, 3], [3, 0]]
#generate lis2 from lis1 based on a condition
>>> lis2 = [[y if y!=3 else y-2 for y in x] for x in lis1]
>>> lis2
[[0, 1], [1, 0]]
#use sets to improve time complexity
>>> s = set(tuple(x) for x in lis2)
#Now use set intersection or a list comprehension to get the
#common elements between lis2 and lis1. Note that set only contains unique items
#so prefer list comprehension if you want all elements from lis that are in lis2
#as well.
>>> [x for x in lis if tuple(x) in s]
[[0, 1], [1, 0]]
>>> s.intersection(map(tuple,lis))
{(0, 1), (1, 0)}