List of Lists: finding a value throughout - python

I am using Python to write a program that looks through lists of lists and changes values.
In my list of lists I have 3's and I want to find their index. Right now I can only get it to work on the first row. I want it to find 3's on any of the lists in "numbers."
Here is some sample code to wash away the mud:
numbers = [
[3, 3, 3, 5, 3, 3, 3, 3, 6],
[8, 0, 0, 0, 4, 7, 5, 0, 3],
[0, 5, 0, 0, 0, 3, 0, 0, 0],
[0, 7, 0, 8, 0, 0, 0, 0, 9],
[0, 0, 0, 0, 1, 0, 0, 0, 0],
[9, 0, 0, 0, 0, 4, 0, 2, 0],
[0, 0, 0, 9, 0, 0, 0, 1, 0],
[7, 0, 8, 3, 2, 0, 0, 0, 5],
[3, 0, 0, 0, 0, 8, 0, 0, 0],
]
a = -1
while a:
try:
for row in numbers:
a = row[a+1:].index(3) + a + 1
print("Found 3 at index", a)
except ValueError:
break
When I run it I get:
Found 3 at index 0
Found 3 at index 1
Found 3 at index 2
Found 3 at index 4
Found 3 at index 5
Found 3 at index 6
Found 3 at index 8
Which shows that it is working but only on the first row.
Thanks!

Here's a little code snippet to get you started:
>>> for i, row in enumerate(numbers):
if 3 in row:
print i, row.index(3)
1 8
2 5
7 3
8 0
>>> numbers[1][8]
3
>>> numbers[2][5]
3
>>> numbers[7][3]
3
>>> numbers[8][0]
3

If you only want to get the row index, iterate over numbers using enumerate [docs] and test whether 3 is in the list using in [docs]:
for index, row in enumerate(numbers):
if 3 in row:
print "3 found in row %i" % index
For row and column index, iterate over both lists:
for index, row in enumerate(numbers):
for col, value in enumerate(row):
if value == 3:
print "3 found in row %i at position %i" % (index, col)
If you just want to get the indexes in a new list, you can use list comprehension [docs]:
indexes = [(row, col) for row, r in enumerate(numbers) for col, val in enumerate(r) if val == 3]

Try the following:
[[i for i, v in enumerate(row) if v == 3] for row in numbers]
This will result in a list of lists where each entry in the inner lists is an index of a 3 in the corresponding row from the original list:
[[], [8], [5], [], [], [], [], [3], [0]]
You said you were looking for 3 but your code appears to be looking for 0, which do you want?
You could use it like this:
threes = [[i for i, v in enumerate(row) if v == 3] for row in numbers]
for row, indices in enumerate(threes):
for col in indices:
print "3 found in row %d, column %d" % (row, col)

Instead of displaying the information, let's actually build up a data structure that gives us the "coordinates" of every 3:
x = [
(r, c)
for r, row in enumerate(numbers)
for c, cell in enumerate(row)
if cell == 3
]
And we can easily verify it:
assert(all(numbers[r][c] == 3 for r, c in x))
But if you want to replace values, it's silly to try to build up this list and then use it to manually go back in and replace stuff. Much cleaner to just produce the desired output directly. That is, "a list of lists such that the value is None (let's say, for the sake of argument) if the corresponding original value is 3, and otherwise the original value)".
That's spelled like
[[None if cell == 3 else cell for cell in row] for row in numbers]

Try using scipy/numpy to do this
import scipy as sp
matrix = your_matrix #write your matrix here. I left it.
x,y = sp.where(matrix == 3)
for i in range(len(x)):
print x[i],y[i]

Related

Accessing neighbour indices in a particular element of an array (python)

I have a two dimensional list like :
data = [[0,0,0,0,0,1,0,0,0,0], [0,1,0,0,0,0,0,0,0,0]]
How can I access the index of the neighbours, where the value equals 1?
Expected output:
[[4, 5, 6], [0, 1, 2]]
For example, the indices of an array data in first row at value 1 is 5, so I need to access its left and right side neighbour indices like 4 and 6. Same way for row 2.
If I understand description well (please clarify) , maybe you can try this one. Additionally, you can check edge case where there is no 1, or no left or right .
import numpy as np
a = np.array([
[0, 0, 0, 0, 0, 1, 0, 0, 0, 0],
[0, 1, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 1, 0, 0, 0, 0, 0, 0, 0, 0]])
if __name__ == "__main__":
indices = np.where(a == 1)[1]
indices = indices.reshape(-1,1)
indices = np.concatenate([indices-1,indices,indices+1],-1)
print(indices)
One efficient solution is using FOR loops:
for i in range(2):
for j in range(10):
if a[i][j]==1:
print(str(i)+' '+str(j))
If using lists, here is a one approach which identifies the indexes of the neighbours of 1. As a caveat, this will fail with a index out of range, if the 1 value is the first of last element in the list.
Input:
data = [[0,0,0,0,0,1,0,0,0,0], [0,1,0,0,0,0,0,0,0,0]]
Example:
[[i-1, i, i+1] for sub in data for i, j in enumerate(sub) if j == 1]
Output:
[[4, 5, 6], [0, 1, 2]]

Mapping a list of elements to a range of an element from another list to create unique matrices

I am trying to "map a list of elements to a range of an element from another list to create unique matrices." Let me explain with a drawing.
Kickstart-inspired question
I hope that it makes sense.
This is inspired by Google Kickstart competition, which means that it is not a question exactly required by the contest.
But I thought of this question and I think that it is worth exploring.
But I am stuck with myself and not being able to move on much.
Here is the code I have, which obviously is not a correct solution.
values = input("please enter your input: ")
values = values.split()
values = [int(i) for i in values]
>>> please enter your input: 2 4 3 1 0 0 1 0 1 1 0 0 1 1 0 6 4 1 0 0 0 1 0 0 1 1 1 1 1 1 0 1 0 1 0 1 0 1 1 1 0
rows_columns = []
matrix = []
for i in values:
if i > 1:
rows_columns[:1].append(i) # The "2" at the very beginning indicates how many matrices should be formed
elif i <= 1:
matrix.append(i)
rows_columns[:1]
>>> [4, 3, 6, 4]
matrix_all = []
for i in range(1, len(rows_columns)):
matrix_sub = []
for j in range(rows_columns[i]):
matrix_sub.append(matrix[j])
if matrix_sub not in matrix_all:
matrix_all.append(matrix_sub)
>>> [[1, 0, 0, 1], [1, 0, 0], [1, 0, 0, 1, 0, 1], [1, 0, 0, 1]]
I really wonder if the nested loop is a good idea to solve this question. This is the best way I could think of for the last couple of hours. What I want to get as a final result looks like below.
Final expected output
Given that there is information about how many rows and columns there should be on a matrix on one list and just enough numbers of elements to form the matrix on the other, what would be the solution to map(or create) the two matrices out of the other list, based on the dimensionality information on a list?
I hope that it is clear, let me know when it is not.
Thanks!
Without using numpy, here is one working solution, based on the input found in your code snippet, and the expected result listed in your final expected result link:
values = [2, 4, 3, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 6, 4, 1, 0, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 1,
0, 1, 0, 1, 0, 1, 1, 1, 0]
v_idx = 1
"""
As per example, the number of matrices desired is found in the first input list element.
In the above values list, we want 2 matrices. The for loop below therefore executes exactly 2 times
"""
for matrix_nr in range(values[0]):
# The nr of rows and nr of columns are the next two elements in the values list
nr_rows = values[v_idx]
nr_cols = values[v_idx + 1]
# Calculate the start index for the next matrix specifications
new_idx = v_idx+2+(nr_rows*nr_cols)
# Slice the values list to extract the values for the current matrix to format
sub_elements = values[v_idx+2: new_idx]
matrix = []
# Append elements to the matrix by slicing values according to nr_rows and nr_cols
for r in range(nr_rows):
start_idx = r*nr_cols
end_idx = (r+1)*nr_cols
matrix.append(sub_elements[start_idx:end_idx])
print(matrix)
v_idx = new_idx
This gives the expected result:
[[1, 0, 0], [1, 0, 1], [1, 0, 0], [1, 1, 0]]
[[1, 0, 0, 0], [1, 0, 0, 1], [1, 1, 1, 1], [1, 0, 1, 0], [1, 0, 1, 0], [1, 1, 1, 0]]
As said, numpy could very likely be used to be a lot more efficient.

Why is this index function showing a 2 instead of a 4?

When I am running the following code, I get 0,1,2,3,2 to be printed out. Why would a 2 be printed as the last number when it should be a 4? The index function should be printing the index of each of the lists inside of the big list, correct? Using Python btw
game_board = [["o", 1, 0, 0, 0],
[2, 2, 0, 0, 0],
[0, 0, 2, 2, 2],
[0, 0, 2, "o", 2],
[0, 0, 2, 2, 2]]
for i in game_board:
print(game_board.index(i))
using the index function of a list returns the first occurrence of an item. Here's a simplified example:
game_board = [0,2,5,2,3]
game_board.index(2)
>>> 1
This returns the first time the number two is seen in your list.
In your example, the row
[0, 0, 2, 2, 2]
is at index 2 and index 4. When iterating over each list and looking for it's index, rows 0, 1, 2, and 3 return correctly but because the row at index 4 is the same at index 2, it will return the number 2.

Count Number Of Occurence in 2D Array

Let's say I have an array like this
grid:
[[1, 1, 0, 0, 0],
[1, 1, 0, 0, 0],
[0, 0, 1, 0, 0],
[0, 0, 0, 1, 1]]
I want to isolate the group of "items" in this case 1's which are three groups the rule being the 0's are used to separate them like intersections. So this example has 3 groups of 1.
If you know how to do this with python, the first question I'd be asked is what I've tried as proof of not handing my homework to the community, the idea I had was to iterate down and left but that would have a high likelihood of missing some numbers since if you think about it, it would form a cross eminating from the top left and well this group is here to learn.
So for me and others who have an interest in this data science like problem be considerate.
If you do not need to know which sets are duplicates, you can use python's set built-in to determine unique items in a list. This can be a bit tricky since set doesn't work on a list of lists. However, you can convert this to a list of tuples, put those back in a list, and then get the len of that list to find out how many unique value sets there are.
grid = [[1, 1, 0, 0, 0],
[1, 1, 0, 0, 0],
[0, 0, 1, 0, 0],
[0, 0, 0, 1, 1]]
unique = [list(x) for x in set(tuple(x) for x in grid)]
unique_count = len(unique) # this will return 3
Relatively straightforward depth first search based implementation of connected component labeling.
def get_components(grid, indicator=1):
def label(g, row, col, group):
if row >= 0 and col >= 0 and row < len(g) and col < len(g[row]) and g[row][col] == -1:
# only label if currently unlabeled
g[row][col] = group
# attempt to label neighbors with same label
label(g, row + 1, col, group)
label(g, row, col + 1, group)
label(g, row - 1, col, group)
label(g, row, col - 1, group)
return True
else:
return False
# initialize label grid as -1 for entries that need labeled
label_grid = [[-1 if gc == indicator else 0 for gc in gr] for gr in grid]
group_count = 0
for row, grid_row in enumerate(grid):
for col in range(len(grid_row)):
if label(label_grid, row, col, group_count + 1):
group_count += 1
return label_grid, group_count
The results of label_grid, group_count = get_components(grid) for your example inputs are
label_grid = [[1, 1, 0, 0, 0],
[1, 1, 0, 0, 0],
[0, 0, 2, 0, 0],
[0, 0, 0, 3, 3]]
group_count = 3
And for cases like the following
grid = [[1 0 1],
[1 1 1]]
we get group_count = 1.

python consecutive counts of an occurence with length

this is probably really easy to do but I am looking to calculate the length of consecutive positive occurrences in a list in python. For example, I have a and I am looking to return b:
a=[0,0,1,1,1,1,0,0,1,0,1,1,1,0]
b=[0,0,4,4,4,4,0,0,1,0,3,3,3,0]
I note a similar question on Counting consecutive positive value in Python array but this only returns consecutive counts but not the length of the belonging group.
Thanks
This is similar to a run length encoding problem, so I've borrowed some ideas from that Rosetta code page:
import itertools
a=[0,0,1,1,1,1,0,0,1,0,1,1,1,0]
b = []
for item, group in itertools.groupby(a):
size = len(list(group))
for i in range(size):
if item == 0:
b.append(0)
else:
b.append(size)
b
Out[8]: [0, 0, 4, 4, 4, 4, 0, 0, 1, 0, 3, 3, 3, 0]
At last after so many tries came up with these two lines.
In [9]: from itertools import groupby
In [10]: lst=[list(g) for k,g in groupby(a)]
In [21]: [x*len(_lst) if x>=0 else x for _lst in lst for x in _lst]
Out[21]: [0, 0, 4, 4, 4, 4, 0, 0, 1, 0, 3, 3, 3, 0]
Here's one approach.
The basic premise is that when in a consecutive run of positive values, it will remember all the indices of these positive values. As soon as it hits a zero, it will backtrack and replace all the positive values with the length of their run.
a=[0,0,1,1,1,1,0,0,1,0,1,1,1,0]
glob = []
last = None
for idx, i in enumerate(a):
if i>0:
glob.append(idx)
if i==0 and last != i:
for j in glob:
a[j] = len(glob)
glob = []
# > [0, 0, 4, 4, 4, 4, 0, 0, 1, 0, 3, 3, 3, 0]

Categories

Resources