Iterating through list of lists of lists - python

I am trying to iterate through a 3-D list in python(not numpy but I am willing to convert to a numpy array if this makes it easier) in such a way that from a list like this:
a = [[[0, 0], [3, 0]], [[1, 0], [4, 0]], [[2, 0], [6, 0]] ]
I can get the output
[0,0]
[1,0]
[2,0]
[3,0]
[4,0]
[6,0]
I can't figure out how to make it iterate like this...
My code:
a = [[[0, 0], [0, 0]], [[1, 0], [0, 0]], [[2, 0], [0, 0]] ]
for i in range(len(a)):
for z in range(len(a[i])):
print(a[i][z])
I've tried different things but can't seem to get this output.

I think you want to print the nth sub-sublists consecutively from each sublist. You could unpack and zip a to get an iterable of tuples, then print each pair in them:
for tpl in zip(*a):
for pair in tpl:
print(pair)
Output:
[0, 0]
[1, 0]
[2, 0]
[3, 0]
[4, 0]
[6, 0]

Try:
print(*[i for v in zip(*a) for i in v], sep="\n")
Prints:
[0, 0]
[1, 0]
[2, 0]
[3, 0]
[4, 0]
[6, 0]

In case you want to just traverse the elements column wise, you can convert the list to numpy array, then stack the columns and print:
import numpy as np
a = [[[0, 0], [3, 0]], [[1, 0], [4, 0]], [[2, 0], [6, 0]] ]
arr = np.stack(np.array(a), axis=1)
for p in arr:
for x in p:
print(x)
The solution below is based on the previous assumption of printing each item in the sublist based on sorted order:
You can use itertools to flatten the 3d to 2d list and then sort the 2d list based on first element in each sublist. Then print the sorted list.
import itertools
a = [[[0, 0], [3, 0]],[[1, 0], [4, 0]],[[2, 0], [6, 0]]]
flat_list = list(itertools.chain(*a))
sorted_list = sorted(flat_list, key=lambda x: x[0])
for i in sorted_list:
print(i)

This is the correct way of iterating like you're trying to do:
a = [[[0, 0], [0, 0]], [[1, 0], [0, 0]], [[2, 0], [0, 0]] ]
for i in range(len(a)):
for z in range(len(a[i])):
print((a[i])[z])
If it is simpler for you, instead of iterating on the length of the lists with an index, try iterating on the elements of the lists:
a = [[[0, 0], [0, 0]], [[1, 0], [0, 0]], [[2, 0], [0, 0]] ]
for a1 in a:
for a2 in a1:
print(a2)

Related

Manipulating an array afterward so that the rows and column depends on the size of two strings

I am trying to manipulate array2 so that the row and column is dependent on the len of the strings as for array1
str1 = "Hi"
str2 = "Bye"
array1 = [[[0, 0] for y in range(len(str2)+1)] for x in range(len(str1)+1)]
print(array1)
#output: [[[0, 0], [0, 0], [0, 0], [0, 0]], [[0, 0], [0, 0], [0, 0], [0, 0]], [[0, 0], [0, 0], [0, 0], [0, 0]]]
array2 = [[0, 1, 2, 3], [1, 2, 3, 4], [2, 3, 4, 5]]
#want array2 to implement same format as array1 where the row and column is determined by the len of str1 and str2
temp = [[[array2[i], array2[j]] for y in range(len(str2)+1)] for x in range(len(str1)+1)] #does not work
I tried to remove some brackets from temp however, did not work.
I tried to manipulate the method I used for array1, but did not work. I was expecting the rows and columns to be dependent on the len of the strings as for array2.
The current code has no idea what to do with array2[i], array2[j] cause neither i nor j have been defined.
This code is working as expected (I've organized the output for better readability):
str1 = "Hi"
str2 = "Bye"
array1 = [[[0, 0] for y in range(len(str2)+1)] for x in range(len(str1)+1)]
print(array1)
#output is 4x3: [
#[[0, 0], [0, 0], [0, 0], [0, 0]],
#[[0, 0], [0, 0], [0, 0], [0, 0]],
#[[0, 0], [0, 0], [0, 0], [0, 0]]]
array2 = [[0, 1, 2, 3], [1, 2, 3, 4], [2, 3, 4, 5]]
temp = [[[0, 0] for y in range(len(str2)+1)] for x in range(len(str1)+1)]
#output is 4x3: [
#[[0, 0], [0, 0], [0, 0], [0, 0]],
#[[0, 0], [0, 0], [0, 0], [0, 0]],
#[[0, 0], [0, 0], [0, 0], [0, 0]]]
If you want to use a certain set of numbers from the array, you need to change the code to:
i, o = 0, 1
temp = [[[array2[i], array2[j]] for y in range(len(str2)+1)] for x in range(len(str1)+1)]
If this doesn't solve your problem, please provide further explanation

Convert adjacency matrix to array of edges

I want to be able to convert an adjacency matrix to array of edges. Currently I know only how to conver an array of edges to adjacency matrix:
E = [[0, 0], [0, 1], [1, 1], [2, 0]]
size = len(set([n for e in E for n in e]))
adjacency_matrix = [[0] * size for _ in range(size)]
for sink, source in E:
adjacency_matrix[sink][source] = 1
>> print(adjacency_matrix)
[[1, 1, 0], [0, 1, 0], [1, 0, 0]]
but is there a possibility to reverse this process?
If you need pure python, use a list comprehension:
adjacency_matrix = [[1, 1, 0], [0, 1, 0], [1, 0, 0]]
E = [[i,j] for i,l in enumerate(adjacency_matrix) for j, x in enumerate(l) if x]
output: [[0, 0], [0, 1], [1, 1], [2, 0]]
Try this
E = np.stack(np.where(adjacency_matrix)).T
Add tolist() if you want a list
Output (with tolist())
[[0, 0], [0, 1], [1, 1], [2, 0]]
EDIT: my bad I thought OP was using numpy, so here it is in numpy
Yes, it's possible and easy, just iterate through your matrix using two nested cycles, for example:
adjacency_matrix = [[1, 1, 0], [0, 1, 0], [1, 0, 0]]
E = []
for i in range(size):
for j in range(size):
if adjacency_matrix[i][j] == 1:
E.append([i, j])
print(E)
Output:
[[0, 0], [0, 1], [1, 1], [2, 0]]
You could make a function for it:
def adj_to_edges(A):
edges = []
for i,row in enumerate(A):
for j,b in enumerate(row):
if b == 1:
edges.append([i,j])
return edges
print(adj_to_edges([[1, 1, 0], [0, 1, 0], [1, 0, 0]]))
#[[0, 0], [0, 1], [1, 1], [2, 0]]

Sort array based on value and create new array

Imagine a two dimensional array:
a = np.array([[1,1],[1, 0],[0, 0],[0, 0],[0, 0],[1, 1],[1, 1],[0, 1]])
I want to sort the array based on its first value like:
[[1,1],[1, 1],[1, 1],[1, 0],[0, 1],[0, 0],[0, 0],[0, 0]]
If I am simply going with a .sort() like:
a[::-1].sort(axis=0)
and the returned array looks like:
array([[1, 1],
[1, 1],
[1, **1**],
[**1**, 1],
[0, 0],
[0, 0],
[0, 0],
[0, 0]])
As you can see the bold 1 used to be a zero. Why is the function flipping around my numbers? I searched the internet and haven't found any answers.
The problem is that numpy sort when you pass axis=0 is sorting each column independently (see examples on doc page). If you want to sort rows, then you can use sorted instead:
np.array(sorted(a, key=lambda x: x.tolist(), reverse=True))
In your case the result is
[[1 1]
[1 1]
[1 1]
[1 0]
[0 1]
[0 0]
[0 0]
[0 0]]
the sort you are doing is a sort of all columns in the array independently of each other,
from the first example on this page https://numpy.org/doc/stable/reference/generated/numpy.sort.html
>>> a = np.array([[1,4],[3,1]])
>>> np.sort(a) # sort along the last axis
array([[1, 4],
[1, 3]])
>>> np.sort(a, axis=None) # sort the flattened array
array([1, 1, 3, 4])
>>> np.sort(a, axis=0) # sort along the first axis
array([[1, 1],
[3, 4]])
also see this answer to sort the rows based on a single column: Sorting arrays in NumPy by column
You can use np.lexsort, and pass the two columns independently, then reverse the order. lexsort returns the sorted indices, given the key. You need to put first column second, because the primary key in lexsort is the last column:
>>> a[np.lexsort((a[:,1], a[:,0]))][::-1]
array([[1, 1],
[1, 1],
[1, 1],
[1, 0],
[0, 1],
[0, 0],
[0, 0],
[0, 0]])
Here is the output of np.lexsort on your data:
key1 key2 (primary)
>>> np.lexsort((a[:,1], a[:,0]))
array([2, 3, 4, 7, 1, 0, 5, 6], dtype=int64)

How to replace ndarray with a number?

I have the following code:
arr = zip(*people2)
for i in range(len(arr)):
for j in range(len(arr[i])):
for k in range(len(arr[i][j])):
if(arr[i][j][k] == 1):
arr[i][j] = k
break
There is an array of arrays of arrays. I need to replace these last arrays with numbers.
Like this:
[
[[1, 0, 0], [2, 0, 0]],
[[3, 0, 0], [4, 0, 0]],
]
->
[
[1, 2],
[3, 4]
]
Numbers here are just for example.
How can I do this? I tried to use numpy.resize(), but it doesn't work.

access elements of a list from a modified list

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)}

Categories

Resources