Nested list in nested loop - python

like extremely new, so please bear with me.
Im trying to increment each element of a nested list by 1
a straight forward list works fine:
a = [1,2,3,4,5,6,7,8]
for i in range(len(a)):
a[i] += 1
but why doesn't it work with:
a = [[1, 2], [3, 4], [5, 6], [7, 8]]
what am i missing?

Let's unroll the loop so we can inspect:
a = [1, 2, 3, 4, 5, 6, 7, 8]
i = 0
assert a[i] == 1 # the zeroeth element of a
a[i] += 1 # increment 1, making it 2
assert a[i] == 2
i = 1
# ... etc, repeat
contrast with
a = [[1, 2], [3, 4], [5, 6], [7, 8]]
i = 0
assert a[i] == [1, 2] # the zeroeth element of a is now the list [1, 2]!
a[i] += 1 # TypeError! What's the logical equivalent of adding 1 to a list? There isn't one

It won't work as you have another list inside list a or nested list. Therefore, you need nested loop:
Following program would help:
a = [[1, 2], [3, 4], [5, 6], [7, 8]]
for i in range(len(a)):
for j in range(len(a[i])):
a[i][j] += 1
Hope it Helps!!!

In the first iteration your a[i] += 1 would effectively be a[0] = [1, 2] + 1. That doesn't exactly make sense. You need to have a second, inner loop.
Use nested for loops:
for i in range(len(a)):
for ii in range(len(a[i])):
a[i][ii] += 1

Because you have nested list then you have to iterate that nested one again
Here a cool way to check if there list inside with recursion
a = [1,[2, 4],3,[4, 5],5,6,7,8]
def increment_a_list(some_list):
for i in range(len(some_list)):
if type(some_list[i]) is list: # if the element is a list then execute the function again with that element
increment_a_list(some_list[i])
else:
some_list[i] += 1 # +1 to that element if it not a list
return some_list
print(increment_a_list(a))

a = [[1, 2], [3, 4], [5, 6], [7, 8]]
Each item in the list is again a list. You need to traverse and incerement each of it individually. So, nested for loop can solve your problem.
A more generic solution - Recursion
### Using recursion - The level of nesting doesn't matter
def incrementor(arr):
for i in range(len(arr)):
if type(arr[i]) is list:
incrementor(arr[i])
else:
arr[i] = arr[i] + 1
a = [[1, 2], [3, 4], [5, 6], [7, 8],9,10,11,12,[13,[14,15,16]],[[17,18],[19,[20,21]]]]
incrementor(a)
print(a)
Output
[[2, 3], [4, 5], [6, 7], [8, 9], 10, 11, 12, 13, [14, [15, 16, 17]], [[18, 19], [20, [21, 22]]]]

Related

How to change the index of a list?

I have two lists like below:
A = [[0, [1, 2]], [1, [3, 4]], [2, [5, 6]], [3, [7, 8]], [4, [9, 10]], [5, [11, 12]], [6, [13, 14]]]
and
B = [[0, [1, 2]], [1, [4, 5]], [4, [[7, 8], [9, 10]]]]
I want to replace some elements of A based on some conditions related to list B.
I have written a code that does what I'm looking for, as below:
x = 3
v = [0, 1, 4]
for i in range (x):
if i in v and B[i][0] == A[i][0]:
A[i][1][0] = B[i][1][1]
for elem in v:
if elem not in range(x):
A[elem][1][0] = B[2][1][1][0]
A[elem+1][1][0] = B[2][1][1][1]
else:
A = A
print (A)
My problem is with these lines:
for elem in v:
if elem not in range (x):
A[elem][1][0] = B[2][1][1][0]
A[elem+1][1][0] = B[2][1][1][1]
As you can see, after looking through the elements of list v, and check if those elements are not in range (x), in this case, that element is 4, I want to replace some elements of A with some elements of B in this case that element is [4, [[7, 8], [9, 10]]] , However, the index of this element in list B is 2. Is there any other way to use 4 in [4, [[7, 8], [9, 10]]] which is also an element of v inside the code instead of writing B[2]? I want to use [x[0] for x in B] as the indicators instead of using the indexes, as those are different.
Thanks
if you want to stick to the structure of your current code, you could use np.where for this
x= 3
v = [0, 1, 4]
import numpy as np
for i in range (x):
if i in v and B[i][0] == A[i][0]:
A [i][1][0] = B[i][1][1]
for elem in v:
if elem not in range (x):
# get index (in this case: 2)
ind = np.where(np.array([i[0] for i in B]) == elem)[0][0]
A [elem][1][0] = B[ind][1][1][0]
A [elem+1][1][0] = B[ind][1][1][1]
else:
A = A
print (A)

Advanced list comprehension: creating averages

I have a list, each element in the list in a list containing 2 numbers separated by a comma.
I have to treat the first items in each list in relation with each other, same with the second ones.
Given a list, I have to replace the first number of each nested list with the average of the number, the first number in the list to its right and the first number in the list to its left. same to the second number.
For the first nested list, I have to replace it the average or the number itself and its matching number in the list to its right.
For the last, the same with the list to its left.
For example:
[[1, 1], [7, 7], [20, 20], [9, 9], [-12, -12]]
would be:
[[(1+7)/2, (1+7)/2], [(7+1+20)/3, (7+1+20)/3], [(20+7+9)/3, (20+7+9)/3], [(9+20-12)/3, (9+20-12)/3], [(-12+9)/2, (-12+9)/2]]
and thus:
[[4, 4], [9, 9], [12, 12], [5, 5], [-2, -2]]
because we are returning ints.
I have a code but it only prints the average, which is kind of clunky. Please help me to point me to the right direction on how to calculate the elements, and create the new list.
Also, I would like to use only loops and basic list comprehensions, so I can understand the logic.
This is my code so far:
def lpf(lst):
for i in range(len(lst)):
for j in range(2):
if i == 0:
lst[i][j] = int((lst[i][j] + lst[i+1][j]) / 2)
elif 0 < i < (len(lst) - 1):
lst[i][j] = int((lst[i-1][j] + lst[i][j] + lst[i+1][j]) / 3)
elif i == len(lst) - 1:
lst[i][j] = int((lst[i-1][j] + lst[i][j]) / 2)
return lst
And we have to assume the items in the list won't always be the same.
I seem to understand my code's problem - Once I change the first element, the next iteration happens over the new element and not the original. Yet I cant think about how to solve this.
You wanted list-comprehension, I give you list-comprehension:
[[sum(s[p] for s in l[i-1 if i > 0 else 0:i+2])//(2 if i in (0,len(l)-1) else 3) for p in range(2)] for i in range(len(l))]
In all serious though, I would recommend breaking this down into a for-loop which contains the inner list-comprehension as it is just so unreadable.
Example of it working:
>>> l = [[1, 1], [7, 7], [20, 20], [9, 9], [-12, -12]]
>>> [[sum(s[p] for s in l[i-1 if i > 0 else 0:i+2])//(2 if i in (0,len(l)-1) else 3) for p in range(2)] for i in range(len(l))]
[[4, 4], [9, 9], [12, 12], [5, 5], [-2, -2]]
Exploded form without list-comprehensions:
output = []
for i in range(len(l)):
if i == 0:
group = l[i:i+2]
averaged = [(group[0][0] + group[1][0])//2,
(group[0][1] + group[1][1])//2]
output.append(averaged)
elif i == len(l)-1:
group = l[i-1:i+1]
averaged = [(group[0][0] + group[1][0])//2,
(group[0][1] + group[1][1])//2]
output.append(averaged)
else:
group = l[i-1:i+2]
averaged = [(group[0][0] + group[1][0] + group[2][0])//3,
(group[0][1] + group[1][1] + group[2][0])//3]
output.append(averaged)
which gives output as before:
[[4, 4], [9, 9], [12, 12], [5, 5], [-2, -2]]
Here's a way you can do it if all your sublist items are always the same:
mylist = [1, 7, 20, 9, -12]
def avg_list(l):
return sum(l)/int(len(l))
avgs = [avg_list(mylist[max(0,i-1):min(len(mylist),i+2)]) for i in range(len(mylist))]
output = [[j, j] for j in avgs]
>>> [[4, 4], [9, 9], [12, 12], [5, 5], [-2, -2]]

Rotating a matrix counter-clockwise changes the original as well

So I currently have a function to rotate a matrix counter-clockwise, the list is always a square grid:
def rotate(m: List[List[int]]) -> None:
temp = m.copy()
if len(m) > 1:
for x in range(len(m)):
for y in range(len(m)):
temp[len(m)-1-y][x] = m[x][y]
m = temp.copy()
I've traced this function repeatedly and to my knowledge it should be working. The problem is that for some reason every change to temp affects the original list. For example,
ORIGINAL =
[[1, 2, 3],
[4, 5, 6],
[7, 8, 9]]
WHAT SHOULD OUTPUT =
[[3, 6, 9],
[2, 5, 8],
[1, 4, 7]]
WHAT ACTUALLY OUTPUTS =
[[3, 6, 1],
[2, 5, 2],
[1, 2, 1]
I am on python ver 3.7.0 and have tried slipicing instead of copying the string too but the same thing happens. Anyone know why?
Since every item in the m list is a reference to a sublist, when you make a copy of the m list by calling m.copy(), it is only copying the references of the sublists without creating new copies of the sublists, which is why every change to the temp list is reflected on the original m list.
You should use copy.deepcopy() instead to make copies of the sublists as well:
from copy import deepcopy
def rotate(m):
temp = deepcopy(m)
if len(m) > 1:
for x in range(len(m)):
for y in range(len(m)):
temp[len(m)-1-y][x] = m[x][y]
return temp
so that:
rotate([
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]
])
returns:
[[3, 6, 9],
[2, 5, 8],
[1, 4, 7]]
Alternatively, you can implement the same matrix rotation by zipping the list of lists and reversing it:
def rotate(m):
return list(zip(*m))[::-1]
import copy
def rotate(m: [[int]]):
temp = copy.deepcopy(m)
if len(m) > 1:
for x in range(len(m)):
for y in range(len(m)):
temp[len(m)-1-y][x] = m[x][y]
return temp
So:
rotate([
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]
])
Output:
[[3, 6, 9],
[2, 5, 8],
[1, 4, 7]]
Example: https://onlinegdb.com/ryGU1jD6X

how to merge two sublists sharing any number in common?(2)

Given that:
list=[[1,2,3],[3,4,5],[5,6],[6,7],[9,10],[10,11]]
I have asked a similar question before, I have tried the code on
how to merge two sublists sharing any number in common?
but I am stuck in my code now.
I want to merge the sublists that share a common number,
e.g. [1,2,3] and [3,4,5] can merge to give [1,2,3,4,5] as they share a common number, 3.
In [[1,2,3],[3,4,5],[5,6]], although [1,2,3] and [3,4,5] share a common number, 3,
[3,4,5] and [5,6] also share a common number, 5, so I want all three of them to merge then gives
[1,2,3,4,5,6].
So for list,
my expected result is:
[[1,2,3,4,5,6,7],[9,10,11]]
I have tried the following code but don't know what is wrong, can anyone help?
s = map(set, list)
for i, si in enumerate(s):
for j, sj in enumerate(s):
if i != j and si & sj:
s[i] = si | sj
s[j] = set()
list=[list(el) for el in s if el]
print list
>>>[[5, 6, 7], [9, 10, 11]]
def merge_containing(input_list):
merged_list = [set(input_list[0])]
i = 0
for sub_list in input_list:
if not set(sub_list).intersection(set(merged_list[i])): # 1
merged_list.append(set()) # 2
i += 1 # 2
merged_list[i].update(set(sub_list)) # 3
return [sorted(sub_list) for sub_list in merged_list] # 4
mylist=[[1,2,3],[3,4,5],[5,6],[6,7],[9,10],[10,11]]
print merge_containing(mylist)
Output:
[[1, 2, 3, 4, 5, 6, 7], [9, 10, 11]]
How does it work:
Check if the sub_list set shares any common member with the current
index set of the merged_list.
If it doesn't, add a new empty set to the merged_list and increment
the index.
Adds the sub_list set to the set at index in the merged_list.
Converts from set to list and return
def merge(list_of_lists):
number_set = set()
for l in list_of_lists:
for item in l:
number_set.add(item)
return sorted(number_set)
if __name__ == '__main__':
list_of_lists = [[1,2,3],[3,4,5],[5,6],[6,7],[9,10],[10,11]]
merged = merge(list_of_lists)
print merged
I'm posting this as a new answer since the OP already accepted my other.
But as pointed out by #Eithos,
the input:
[[3,4], [1,2], [1,3]]
should return
[[1,2,3,4]]
and the input
[[1,2,3],[3,4,5],[5,6],[6,7],[9,10],[10,11],[65,231,140], [13,14,51]]
should return
[[1, 2, 3, 4, 5, 6, 7], [9, 10, 11], [13, 14], [51], [65], [140], [231]]
Here's my attempt:
from itertools import chain
def merge_containing(input_list):
print " input:", input_list
chain_list = sorted(set(chain(*input_list))) # 1
print " chain:",chain_list
return_list = []
new_sub_list = []
for i, num in enumerate(chain_list):
try:
if chain_list[i + 1] == chain_list[i] + 1: # 2
new_sub_list.append(num)
else:
new_sub_list.append(num) # 3
return_list.append(new_sub_list)
new_sub_list = []
except IndexError:
new_sub_list.append(num) # 3
return_list.append(new_sub_list)
print 'result:', return_list
return return_list
mylist = [[3,4], [1,2], [1,3]]
merge_containing(mylist)
print
mylist = [[1,2,3],[3,4,5],[5,6],[6,7],[9,10],[10,11],[65,231,140], [13,14,51]]
merge_containing(mylist)
Output:
input: [[3, 4], [1, 2], [1, 3]]
chain: [1, 2, 3, 4]
result: [[1, 2, 3, 4]]
input: [[1, 2, 3], [3, 4, 5], [5, 6], [6, 7], [9, 10], [10, 11], [65, 231, 140], [13, 14, 51]]
chain: [1, 2, 3, 4, 5, 6, 7, 9, 10, 11, 13, 14, 51, 65, 140, 231]
result: [[1, 2, 3, 4, 5, 6, 7], [9, 10, 11], [13, 14], [51], [65], [140], [231]]
Explanation:
This one is a little hacky them the last one
I use itertool.chain to flat all the lists and them I sort it.
Then I check if the current number is within the range of 1 digit from the next
If it is I store it in the new_sub_list, if not I store in the new_sub_list, then store new_sub_list in the return_list, and empty the new_sub_list.
Note the try/except Index Error, it to avoid comparing the last item of the list with one that doesn't exist,
Well... I couldn't resist answering #f.rodrigues' last answer with one of my own.
I have to be honest though, this final version was heavily influenced by jonrsharpe's solution (the code went through various revisions, each one more efficient until I realized his method was the only way to press the most amount of juice) over here: Using sublists to create new lists where numbers don't repeat
Which made me wonder... why are we answering the same question over and over again (from the very same person)? This question, how to merge two sublists sharing any number in common? and the one with jonrsharpe's solution.
Anyway, this joins lists in the way outlined in his first question, but, like the solutions he already received over there, this one also works just as well for solving this problem.
sequence = [[1, 4, 9], [2, 3, 6], [4, 13, 50], [13, 23, 29], [2, 3, 7]]
def combineSequences(seq):
for index, y in enumerate(seq):
while True:
for x in seq[index + 1:]:
if any(i in x for i in seq[index]):
seq.remove(x)
y.extend(x)
break
else:
index += 1
break
return [sorted(set(l)) for l in seq]
sequence = [[1, 4, 9], [2, 3, 6], [4, 13, 50], [13, 23, 29], [2, 3, 7]]
print combineSequences(sequence)
>>> [[1, 4, 9, 13, 23, 29, 50], [2, 3, 6, 7]]
sequence = [[3, 4], [1, 2], [1, 3]]
print combineSequences(sequence)
>>> [[1, 2, 3, 4]]
This solution operates under a different assumption than the one I made earlier, just to clarify. This simply joins lists that have a common number. If the idea, however, was to only have them separated by intervals of 1, see my other answer.
That's it!
Okay. This solution may be difficult to grasp at first, but it's quite logical and succint, IMO.
The list comprehension basically has two layers. The outer layer will itself create separate lists
for each value of i (outer index) that satisfies the condition that the value it points to in the list is not equal to the value pointed to by the previous index + 1. So every numerical jump greater than one will create a new list within the outer list comprehension.
The math around the second (inner list comprehension) condition is a bit more complicated to explain, but essentially the condition seeks to make sure that the inner list only begins counting from the point where the outer index is at, stopping to where once again there is a numerical jump greater than one.
Assuming an even more complicated input:
listVar=[[1,2,3],[3,4,5],[5,6],[6,7],[9,10],[10,11],[65,231,140], [13,14,51]]
# Flattens the lists into one sorted list with no duplicates.
l = sorted(set([x for b in listVar for x in b]))
lGen = xrange(len(l))
print [
[l[i2] for i2 in lGen if l[i2] + i == l[i] + i2]
for i in lGen if l[i] != l[i-1] + 1
]
>>> [[1, 2, 3, 4, 5, 6, 7], [9, 10, 11], [13, 14], [51], [65], [140], [231]]

How can I merge lists that have common elements within a list of lists?

I have a list like [[1, 2, 4], [2, 5], [0, 3, 7, 8], [12, 3, 6], [18, 14]]. How can I get a list that contains lists of all the lists that contain overlapping elements added together? For the example input, the result should be [[1, 2, 4, 5], [0, 3, 6, 7, 8, 12], [14, 18]].
a = [[1, 2, 4], [2, 5], [0, 3, 7, 8], [12, 3, 6], [18, 14]]
result = []
for s in a:
s = set(s)
for t in result:
if t & s:
t.update(s)
break
else:
result.append(s)
This will go one-by-one through the list and create a set from the current sublist (s). Then it will check in the results, if there is another set t that has a non-empty intersection with it. If that’s the case, the items from s are added to that set t. If there is no t with a non-empty intersection, then s is a new independent result and can be appended to the result list.
A problem like this is also a good example for a fixed-point iteration. In this case, you would look at the list and continue to merge sublists as long as you could still find lists that overlap. You could implement this using itertools.combinations to look at pairs of sublists:
result = [set(x) for x in a] # start with the original list of sets
fixedPoint = False # whether we found a fixed point
while not fixedPoint:
fixedPoint = True
for x, y in combinations(result, 2): # search all pairs …
if x & y: # … for a non-empty intersection
x.update(y)
result.remove(y)
# since we have changed the result, we haven’t found the fixed point
fixedPoint = False
# abort this iteration
break
One way I can think of doing this is through recursion. Start with one item, then loop until you find every number it's connected to. For each of these numbers, you must do the same. Hence the recursion. To make it more efficient, store numbers you've visited in a list and check it at the beginning of each recursive sequence to make sure you don't repeat any explorations.
A two liner:
a_set = [set(x) for x in a]
result = [list(x.union(y)) for i,x in enumerate(a_set) for y in a_set[i:]
if x.intersection(y) and x != y]
I have left the last step for you:
a = [[1, 2, 4], [2, 5], [0, 3, 7, 8], [12, 3, 6], [18, 14]]
result = [[1, 2, 4, 5], [0, 3, 6, 7, 8, 12], [14, 18]]
# each sub list
result2 = []
count = 0
print a
for sub_list in a:
print count
print "sub_list: " + str(sub_list)
a.pop(count)
print "a: " + str(a)
#each int
sub_list_extend_flag = False
for int_in_sub_list in sub_list:
print "int_in_sub_list: " + str(int_in_sub_list)
for other_sub_list in a:
print "current_other_sub_list: " + str(other_sub_list)
if int_in_sub_list in other_sub_list:
sub_list_extend_flag = True
other_sub_list.extend(sub_list)
result2.append(list(set(other_sub_list)))
if not sub_list_extend_flag:
result2.append(sub_list)
count += 1
print result2
Simple answer:
a = [[1, 2, 4], [2, 5], [0, 3, 7, 8], [12, 3, 6], [18, 14]]
for x in a:
for y in x:
print y
its more simple than first one:
box=[]
a = [[1, 2, 4], [2, 5], [0, 3, 7, 8], [12, 3, 6], [18, 14]]
for x in a:
for y in x:
box.append(y)
print box
Result:[1, 2, 4, 2, 5, 0, 3, 7, 8, 12, 3, 6, 18, 14]
And with this, you can compare the numbers:
box=[]
box2=""
a = [[1, 2, 4], [2, 5], [0, 3, 7, 8], [12, 3, 6], [18, 14]]
for x in a:
for y in x:
box.append(y)
print box
for a in box:
box2+=str(a)
print box2
Result: 12425037812361814
Also you can make it more cute:
print " ".join(box2)
Result: 1 2 4 2 5 0 3 7 8 1 2 3 6 1 8 1 4

Categories

Resources