How to modify the elements in a list within list - python

I am very new to Python, trying to learn the basics. Have a doubt about the list.
Have a list:
L = [[1,2,3],[4,5,6],[3,4,6]]
The output should be:
[[2,4,6],[8,10,12],[6,8,12]]
The code that works for me is the following
for x in range(len(L)):
for y in range(len(L[x])):
L[x][y] = L[x][y] + L[x][y]
print L
It gives the output [[2,4,6],[8,10,12],[6,8,12]].
Now I want the same output with a different code:
for x in L:
a = L.index(x)
for y in L[a]:
b = L[a].index(y)
L[a][b] = L[a][b] + L[a][b]
print L
With the above code the output obtained is:
[[4,2,6],[8,10,12],[12,8,6]]
I tried to debug about the above output.
I put a print statement above the line "L[a][b] = L[a][b] + L[a][b]" for printing a and b. I was surprised to see the values of a and b are :
0,0
0,0
0,2
1,0
1,1
1,2
2,0
2,1
2,0
Again if I comment out the line "L[a][b] = L[a][b] + L[a][b]" then the values of a and b are as expected:
0,0
0,1
0,2
1,0
1,1
1,2
2,0
2,1
2,2
I suspect this might be happening due to the scope of variable in python and tried to study few stuffs about scoping in python. But I didn't get appropriate answer neither for scoping or the above question.

You modifying your list with statement - L[a][b] = L[a][b] + L[a][b]
e.g. -
L = [[1, 2, 3], [4, 5, 6], [3, 4, 6]]
L[0][0] = 1 initially
Then you modify it as L[0][0] = 2
L = [[2, 2, 3], [4, 5, 6], [3, 4, 6]]
In next loop you search index for 2, which is 0,0 now, Because you modified list L.
I tried to print L along with a,b in your example. Result explains the behavior -
0 0
[[1, 2, 3], [4, 5, 6], [3, 4, 6]]
0 0
[[2, 2, 3], [4, 5, 6], [3, 4, 6]]
0 2
[[4, 2, 3], [4, 5, 6], [3, 4, 6]]
1 0
[[4, 2, 6], [4, 5, 6], [3, 4, 6]]
1 1
[[4, 2, 6], [8, 5, 6], [3, 4, 6]]
1 2
[[4, 2, 6], [8, 10, 6], [3, 4, 6]]
2 0
[[4, 2, 6], [8, 10, 12], [3, 4, 6]]
2 1
[[4, 2, 6], [8, 10, 12], [6, 4, 6]]
2 0
[[4, 2, 6], [8, 10, 12], [6, 8, 6]]

As other people have explained, when you use the index function, it finds the first occurrence of the value you are search for. So the first time through you're loop (for the first row), it looks like
b = 1
[1,2,3].find(1) # returns index 0
#Then you modify the first element of the list
b = 2
[2,2,3].find(2) #returns index 0 again!
For getting the indices in an easier, more deterministic way, you can use the enumerate function on a list. It will provided you with an iterator that returns the index AND value as you move throughout a list.
for rowInd, x in enumerate(L):
for colInd, y in enumerate(x):
L[rowInd][colInd] = y + y
Note that this will do it in place, as in your original solution.
L = [[2, 4, 6], [8, 10, 12], [6, 8, 12]]

The best way to achieved your desired output is to use a list comprehension. You could do as follows:
L = [[1,2,3], [4,5,6], [3,4,6]]
answer = [[2*el for el in sublist] for sublist in L]
print(answer)
Output
[[2, 4, 6], [8, 10, 12], [6, 8, 12]]
This iterates over each sublist in your list L and multiplies each el in the sublist by 2, thus achieving the desired result.

I think the following piece of code might be better
for x in L: #iterating over the orig list
for y in x: #iterating over the inner list
[x][y] = [x][y] + [x][y]

If you insist on using your second method, then you need to store the results in a temporary variable:
L = [[1, 2, 3], [4, 5, 6], [3, 4, 6]]
M = [[0 for y in range(3)] for x in range(3)]
for x in L:
a = L.index(x)
for y in L[a]:
b = L[a].index(y)
M[a][b] = L[a][b] + L[a][b]
L = M
print L
Output:
[[2, 4, 6], [8, 10, 12], [6, 8, 12]]

Related

Python - doing maths with a nested list

If I have a nested list, e.g. x = [[1, 2, 3], [2, 4, 6], [3, 5, 7]], how can I calculate the difference between all of them? Let's called the lists inside x - A, B, and C. I want to calculate the difference of A from B & C, then B from A & C, then C from A & B, then put them in a list diff = [].
My problem is correctly indexing the numbers and using them to do maths with corresponding elements in other lists.
This is what I have so far:
for i in range(len(x)):
diff = []
for j in range(len(x)):
if x[i]!=x[j]:
a = x[i]
b = x[j]
for h in range(len(a)):
d = a[h] - b[h]
diff.append(d)
Essentially for the difference of A to B it is ([1-2] + [2-4] + [3-6])
I would like it to return: diff = [[diff(A,B), diff(A,C)], [diff(B,A), diff(B,C)], [diff(C,A), diff(C,B)]] with the correct differences between points.
Thanks in advance!
Your solution is actually not that far off. As Aniketh mentioned, one issue is your use of x[i] != x[j]. Since x[i] and x[j] are arrays, that will actually always evaluate to false.
The reason is that python will not do a useful comparison of arrays by default. It will just check if the array reference is the same. This is obviously not what you want, you are trying to see if the array is at the same index in x. For that use i !=j.
Though there are other solutions posted here, I'll add mine below because I already wrote it. It makes use of python's list comprehensions.
def pairwise_diff(x):
diff = []
for i in range(len(x)):
A = x[i]
for j in range(len(x)):
if i != j:
B = x[j]
assert len(A) == len(B)
item_diff = [A[i] - B[i] for i in range(len(A))]
diff.append(sum(item_diff))
# Take the answers and group them into arrays of length 2
return [diff[i : i + 2] for i in range(0, len(diff), 2)]
x = [[1, 2, 3], [2, 4, 6], [3, 5, 7]]
print(pairwise_diff(x))
This is one of those problems where it's really helpful to know a bit of Python's standard library — especially itertools.
For example to get the pairs of lists you want to operate on, you can reach for itertools.permutations
x = [[1, 2, 3], [2, 4, 6], [3, 5, 7]]
list(permutations(x, r=2))
This gives the pairs of lists your want:
[([1, 2, 3], [2, 4, 6]),
([1, 2, 3], [3, 5, 7]),
([2, 4, 6], [1, 2, 3]),
([2, 4, 6], [3, 5, 7]),
([3, 5, 7], [1, 2, 3]),
([3, 5, 7], [2, 4, 6])]
Now, if you could just group those by the first of each pair...itertools.groupby does just this.
x = [[1, 2, 3], [2, 4, 6], [3, 5, 7]]
list(list(g) for k, g in groupby(permutations(x, r=2), key=lambda p: p[0]))
Which produces a list of lists grouped by the first:
[[([1, 2, 3], [2, 4, 6]), ([1, 2, 3], [3, 5, 7])],
[([2, 4, 6], [1, 2, 3]), ([2, 4, 6], [3, 5, 7])],
[([3, 5, 7], [1, 2, 3]), ([3, 5, 7], [2, 4, 6])]]
Putting it all together, you can make a simple function that subtracts the lists the way you want and pass each pair in:
from itertools import permutations, groupby
def sum_diff(pairs):
return [sum(p - q for p, q in zip(*pair)) for pair in pairs]
x = [[1, 2, 3], [2, 4, 6], [3, 5, 7]]
# call sum_diff for each group of pairs
result = [sum_diff(g) for k, g in groupby(permutations(x, r=2), key=lambda p: p[0])]
# [[-6, -9], [6, -3], [9, 3]]
This reduces the problem to just a couple lines of code and will be performant on large lists. And, since you mentioned the difficulty in keeping indices straight, notice that this uses no indices in the code other than selecting the first element for grouping.
Here is the code I believe you're looking for. I will explain it below:
def diff(a, b):
total = 0
for i in range(len(a)):
total += a[i] - b[i]
return total
x = [[1, 2, 3], [2, 4, 6], [3, 5, 7]]
differences = []
for i in range(len(x)):
soloDiff = []
for j in range(len(x)):
if i != j:
soloDiff.append(diff(x[i],x[j]))
differences.append(soloDiff)
print(differences)
Output:
[[-6, -9], [6, -3], [9, 3]]
First off, in your explanation of your algorithm, you are making it very clear that you should use a function to calculate the differences between two lists since you will be using it repeatedly.
Your for loops start off fine, but you should have a second list to append diff to 3 times. Also, when you are checking for repeats you need to make sure that i != j, not x[i] != x[j]
Let me know if you have any other questions!!
this is the simplest solution i can think:
import numpy as np
x = [[1, 2, 3], [2, 4, 6], [3, 5, 7]]
x = np.array(x)
vectors = ['A','B','C']
for j in range(3):
for k in range(3):
if j!=k:
print(vectors[j],'-',vectors[k],'=', x[j]-x[k])
which will return
A - B = [-1 -2 -3]
A - C = [-2 -3 -4]
B - A = [1 2 3]
B - C = [-1 -1 -1]
C - A = [2 3 4]
C - B = [1 1 1]

Out of multiple lists, how do I find and return the list that contains the value I want?

a = [1,2,3,4]
b = [5,6,7,8]
c = [9,10,11,12]
If I want to search for 6, the code should return b
Similarly
a = [[1, 2], [3, 4], [5, 6], [8, 7]]
If I want to search for [2,5], the code should return 0 and 2 because the elements 2 and 5 are in a[0] and a[2] respectively.
This is what I have done so far.
x = []
x.append(a)
x.append(b)
x.append(c)
print(x)
Output:[[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]]
If I want to search for 5, the following code will return the index of 5. I want to know if there is a better way to solve this & want to know how to solve the second part.
for i in range(len(x)):
if(5 in x[i]):
print(i)
else:
continue
Output:1
for 1st part:
a = [1,2,3,8]
b = [5,6,7,8]
c = [9,10,11,12]
l = np.array(list(zip(a,b,c))).T
res = np.where(np.isin(l, [2,5]))[0]
l:
array([[ 1, 2, 3, 8],
[ 5, 6, 7, 8],
[ 9, 10, 11, 12]])
res:
array([0, 1])
for 2nd part:
a = [[1, 2], [3, 4], [5, 6], [8, 7]]
res = np.where(np.isin(a, [2,5,1]))[0]
res:
array([0, 0, 2])
Try the below code. I believe this should give the correct output
x = [[1, 2], [3, 4], [5, 6], [8, 7]]
y = [2,5]
for i in y:
for c, j in enumerate(x):
for k in j:
if i == k:
print(c)
It basically traverses the each list in x to find the values in y list.

How to properly structure a for loop for looping through python list

Let's say I have a list A = [1,2,3,4]
I want to show the lists [1,2,3] , [2,3,4]
Here's my solution:
A= [5, 3, 3]
def solution(A):
A.sort()
#print(A)
for i in range(0,len(A)-2):
if i+3 <= len(A):
part = A[i:i+3]
if part[0] + part[1] > part[2]:
print(part)
return 1
I used if i+3 <= len(A):
condition to check length overflow.I don't like the structure, is there a better way to represent this?
This is probably what you want.
for a in range(len(A)-2):
print(list(A[a:a+3]))
>>> [list(A[a:a+3]) for a in range(len(A)-2)]
[[1, 2, 3], [2, 3, 4], [3, 4, 5], [4, 5, 6], [5, 6, 7], [6, 7, 8], [7, 8, 9]]

creating combinations from a list of lists

Im trying to figure out how to take a list of lists of integers and create a new list that contains combinations from the list of lists. I want the combination to start with a value from the first list and then respectively take 1 from each of the subsequent lists, only if the value is greater than the previous list.
l=[[1,2,3],[4,8],[5,10]]
# the answer would look like this
correct=[[1,4,5],[1,4,10],[1,8,10],[2,4,5],[2,4,10],[2,8,10],[3,4,5],[3,4,10],[3,8,10]]
>>> from itertools import product
...
...
... def combos(lst):
... result = []
... for p in product(*lst):
... if all(a < b for a, b in zip(p, p[1:])):
... result.append(list(p))
... return result
...
>>> lst = [[1, 2, 3], [4, 8], [5, 10]]
>>> correct = [[1, 4, 5], [1, 4, 10], [1, 8, 10], [2, 4, 5], [2, 4, 10],
... [2, 8, 10], [3, 4, 5], [3, 4, 10], [3, 8, 10]]
>>> combos(lst) == correct
True
List comprehension is probably a great way to go. It works nicely because of your constraints. You probably want something like:
[[i,j,k] for i in l[0] for j in l[1] if j>i for k in l[2] if k>j]
>>> [[1, 4, 5],
[1, 4, 10],
[1, 8, 10],
[2, 4, 5],
[2, 4, 10],
[2, 8, 10],
[3, 4, 5],
[3, 4, 10],
[3, 8, 10]]
This makes a list of lists of the form [i,j,k] for all the i's in l[0] for all the j's in l[1] if j>i and for all the k's in l[2] if k>j (since we already know that j>i at this point)
However, the code above only works for an input list of list of length 3. Took me a little bit, but this recursive approach should work for a input list of any length
def list_of_lists(in_list):
full_list=[]
def recurse(so_far, l):
if l==len(in_list):
return so_far
next_list = in_list[l]
for i in next_list:
if i>so_far[-1]:
new_list = recurse(so_far.copy()+[i], l+1)
if new_list:
full_list.append(new_list)
for i in in_list[0]:
recurse([i],1)
return full_list
l=[[1,2,3],
[4,8],
[5,10]]
ansList = []
for i in range(len(l[0])):
for j in range(len(l[1])):
for k in range(len(l[2])):
if l[0][i]<l[1][j] and l[1][j]<l[2][k]:
ansList.append([l[0][i],l[1][j],l[2][k]])
print(ansList)

Return min/max of multidimensional in Python?

I have a list in the form of
[ [[a,b,c],[d,e,f]] , [[a,b,c],[d,e,f]] , [[a,b,c],[d,e,f]] ... ] etc.
I want to return the minimal c value and the maximal c+f value. Is this possible?
For the minimum c:
min(c for (a,b,c),(d,e,f) in your_list)
For the maximum c+f
max(c+f for (a,b,c),(d,e,f) in your_list)
Example:
>>> your_list = [[[1,2,3],[4,5,6]], [[0,1,2],[3,4,5]], [[2,3,4],[5,6,7]]]
>>> min(c for (a,b,c),(d,e,f) in lst)
2
>>> max(c+f for (a,b,c),(d,e,f) in lst)
11
List comprehension to the rescue
a=[[[1,2,3],[4,5,6]], [[2,3,4],[4,5,6]]]
>>> min([x[0][2] for x in a])
3
>>> max([x[0][2]+ x[1][2] for x in a])
10
You have to map your list to one containing just the items you care about.
Here is one possible way of doing this:
x = [[[5, 5, 3], [6, 9, 7]], [[6, 2, 4], [0, 7, 5]], [[2, 5, 6], [6, 6, 9]], [[7, 3, 5], [6, 3, 2]], [[3, 10, 1], [6, 8, 2]], [[1, 2, 2], [0, 9, 7]], [[9, 5, 2], [7, 9, 9]], [[4, 0, 0], [1, 10, 6]], [[1, 5, 6], [1, 7, 3]], [[6, 1, 4], [1, 2, 0]]]
minc = min(l[0][2] for l in x)
maxcf = max(l[0][2]+l[1][2] for l in x)
The contents of the min and max calls is what is called a "generator", and is responsible for generating a mapping of the original data to the filtered data.
Of course it's possible. You've got a list containing a list of two-element lists that turn out to be lists themselves. Your basic algorithm is
for each of the pairs
if c is less than minimum c so far
make minimum c so far be c
if (c+f) is greater than max c+f so far
make max c+f so far be (c+f)
suppose your list is stored in my_list:
min_c = min(e[0][2] for e in my_list)
max_c_plus_f = max(map(lambda e : e[0][2] + e[1][2], my_list))

Categories