How to get the index of specific item in python matrix - python

I am newbie to Python programming language. And I am looking for How to get the indexes (line and column ) of specific element in matrix.
In other I way I want to do the same as this source code using lists.
myList=[1,10,54,85]
myList.index(54)
Best Regards

Here's a simple function which returns the coordinates as a tuple (or None if no index is found). Note that this is for 2D matrices, and returns the first instance of the element in the matrix.
(Edit: see hiro protagonist's answer for an alternative Pythonic version)
def find(element, matrix):
for i in range(len(matrix)):
for j in range(len(matrix[i])):
if matrix[i][j] == element:
return (i, j)
Or, if you want to find all indexes rather than just the first:
def findall(element, matrix):
result = []
for i in range(len(matrix)):
for j in range(len(matrix[i])):
if matrix[i][j] == element:
result.append((i, j))
return result
You can use it like so:
A = [[5, 10],
[15, 20],
[25, 5]]
find(25, A) # Will return (2, 0)
find(50, A) # Will return None
findall(5, A) # Will return [(0, 0), (2, 1)]
findall(4, A) # Will return []

a (in my opinion) more pythonic version of FlipTack's algorithm:
def find(element, matrix):
for i, matrix_i in enumerate(matrix):
for j, value in enumerate(matrix_i):
if value == element:
return (i, j)
in python it is often more natural to iterate over elements of lists instead of just the indices; if indices are needed as well, enumerate helps. this is also more efficient.
note: just as list.index (without a second argument) this will only find the first occurrence.

Since you say that you're a beginner, pardon me if you already know some of the below. Just in case I'll describe the basic logic you can use to write your own function or understand the other answers posted here better:
To access an element in a specific row of a list, for example, if you wanted to get the first element and save it in a variable:
myList=[1,10,54,85]
myvar = myList[0] # note that you access the first element with index 0
myvar now stores 1. Why index 0? Think of the index as an indicator of "how far away from the beginning of the list an element is." In other words, the first element is a distance of 0 from the start.
What if you have a multi-dimensional list like so?
multi = [[0, 1, 2],
[3, 4, 5],
[6, 7, 8]
]
Now you think in terms of row and column (and of course you could have n-dimensional lists and keep going).
How to retrieve the 5? That is a distance of 1 row from the start of the list of rows and 2 columns away from the start of the sub-list.
Then:
myvar = multi[1][2]
retrieves the 5.
FlipTack's and hiro protagonist's functions wrap this logic in the nice compact procedures, which search the entire 2-dimensional list, comparing elements until the desired one is found, then returning a tuple of the indices or continuing to search for duplicate elements. Note that if your lists are guaranteed to sorted you can then use a binary search algorithm across rows and columns and get the answer faster, but no need to worry about that for now.
Hopefully this helps.

You can also add a tag to your function to search the occurrences of your input matrix/list.
For example:
If you input is 1D vector:
def get_index_1d(a = [], val = 0, occurrence_pos = False):
if not occurrence_pos:
for k in range(len(a)):
if a[k] == val:
return k
else:
return [k for k in range(len(a)) if a[k] == val]
Output:
a = [1,10,54,85, 10]
index = get_index_1d(a, 10, False)
print("Without occurrence: ", index)
index = get_index_1d(a, 10, True)
print("With occurrence: ", index)
>>> Without occurrence: 1
>>> With occurrence: [1, 4]
For 2D vector:
def get_index_2d(a = [], val = 0, occurrence_pos = False):
if not occurrence_pos:
for k in range(len(a)):
for j in range(len(a[k])):
if a[k][j] == val:
return (k, j)
else:
return [(k, j) for k in range(len(a)) for j in range(len(a[k])) if a[k][j] == val]
Output:
b = [[1,2],[3,4],[5,6], [3,7]]
index = get_index_2d(b, 3, False)
print("Without occurrence: ", index)
index = get_index_2d(b, 3, True)
print("With occurrence: ", index)
>>> Without occurrence: (1, 0)
>>> With occurrence: [(1, 0), (3, 0)]

Just wanted to throw another solution since I didn't see it above:
def find(matrix, value):
value_indexs = [ ( matrix.index(row), row.index(value) ) for row in matrix if value in row]
return value_indexs
Example:
matrix = [
[0, 1, 2],
[3, 4, 5, 6],
[7, 8, 9, 0]
]
find(matrix, 0)
Returns: [(0,0), (2,3)]

Related

Merging two sorted arrays in python

I am trying to merge two sorted arrays recursively, and I can merge the first few numbers until one pointer exits the array. There seems to be some problem with the base case not getting executed. I have tried to print the new_arr with the pointers for each recursive call to debug but cannot seem to find a solution. Here is my code:
new_arr= []
i= 0
j=0
def merge(arr1, arr2, i, j):
#base case
##when arr1 pointer exits
print(i,j, new_arr)
if(i>len(arr1)-1):
new_arr.append(arr2[j:])
return new_arr
##when arr2 pointer exits
if (j > len(arr2)-1):
new_arr.append(arr1[i:])
return new_arr
if(arr1[i]<arr2[j]):
new_arr.append(arr1[i])
i+=1
merge(arr1, arr2, i, j)
elif(arr1[i]>=arr2[j]):
new_arr.append(arr2[j])
j+=1
merge(arr1, arr2, i, j)
sortedarr = merge([1,9], [3,7,11,14,18,99], i, j)
print(sortedarr)
and here goes my output:
0 0 []
1 0 [1]
1 1 [1, 3]
1 2 [1, 3, 7]
2 2 [1, 3, 7, 9]
None
These are the issues:
new_arr.append(arr2[j:]) should be new_arr.extend(arr2[j:]). append is for appending one item to the list, while extend concatenates a second list to the first. The same change needs to happen in the second case.
As you count on getting the mutated list as a returned value, you should not discard the list that is returned by the recursive call. You should return it back to the caller, until the first caller gets it.
It is a bad idea to have new_arr a global value. If the main program would call the function a second time for some other input, new_arr will still have its previous values, polluting the result of the next call.
Although the first two fixes will make your function work (for a single test), the last issue would best be fixed by using a different pattern:
Let the recursive call return the list that merges the values that still needed to be analysed, i.e. from i and j onwards. The caller is then responsible of prepending its own value to that returned (partial) list. This way there is no more need of a global variable:
def merge(arr1, arr2, i, j):
if i >= len(arr1):
return arr2[j:]
if j >= len(arr2):
return arr1[i:]
if arr1[i] < arr2[j]:
return [arr1[i]] + merge(arr1, arr2, i + 1, j)
else:
return [arr2[j]] + merge(arr1, arr2, i, j + 1)
sortedarr = merge([1,9], [3,7,11,14,18,99], i, j)
print(sortedarr)
Note that Python already has a built-in function that knows how to merge sorted arrays, heapq.merge.
list(heapq.merge((1, 3, 5, 7), (2, 4, 6, 8)))
[1, 2, 3, 4, 5, 6, 7, 8]

Where am I going wrong with enumerate?

I know the answer is probably super simple, but I'm absolutely stuck on this short piece of code. The function has no effect on the input list when I run it.
def squareEven(array):
for idx, val in enumerate(array):
if idx % 2 == 0:
val = val * val
else:
val = val
return array
array = [1, 2, 4, 9, 20]
print(squareEven(array))
You can also use the list comprehension to construct a new list with squared values when the index is even.
def squareEven(array):
return [v**2 if i % 2 == 0 else v for (i, v) in enumerate(array)]
https://docs.python.org/3/tutorial/datastructures.html#list-comprehensions
Here are two ways, one bad, one good:
def squareEven(array):
for idx in range(len(array)):
if idx % 2 == 0:
array[idx] = array[idx] * array[idx]
return array
array = [1, 2, 4, 9, 20]
print(squareEven(array))
This is better, because it doesn't damage the original array as a side effect:
def squareEven(array):
new = []
for idx,val in enumerate(array):
if idx % 2 == 0:
new.append(val * val)
else:
new.append(val)
return new
array = [1, 2, 4, 9, 20]
print(squareEven(array))
The reason is that the enumerate function does not actually change the array itself but just returns the new one for you to use in the loop. The simple solution is to save the enumerate(array) into another variable and return it at the end of your function. Keep in mind, you will get an enumerated array at the end. You could map it to convert to a form you initially passed.
In the function, you wrote you don't save the actual result. The variable val you used is temporary and changing it doesn't affect the array you passed. It means that val has the value from the array but not reference to the element. To solve the issue, you can directly change the element by referencing it with idx.

Finding a string in a string in a list python

What I've got at the moment is a grid, which looks like this:
--d--
--d--
-d---
---d-
-d-d-
I'm trying to find the location of each 'd' within the grid. I am able to do this using a simple for loop, however I encounter a problem when I try to find the two 'd's on the same line, it only finds the first one and not the second one. However since it is in a list format (not 100% sure if I can change it out of that format) the .find() method will not work. Not sure if there's a simple way to solve this or if I need to completely re-think my approach but any help would be useful.
Code for the search that I've got at the moment(without the attempt to search for multiple occurrences as it broke everything)
Assume board is the grid mentioned earlier
dirtyCellLocations = []
for idx, row in enumerate(board):
for letter in row:
if letter == 'd':
dirtyLocation = (idx, row.index('d'))
dirtyCellLocations.append(dirtyLocation)
If you're interested the way the grid was formed is with this
board = [[j for j in raw_input().strip()] for i in range(5)]
If you have a board like so
board = ['--d--',
'--d--',
'-d---',
'---d-',
'-d-d-']
You could do
for row in range(len(board)):
for col, value in enumerate(board[row]):
if value == 'd':
print('[{},{}]'.format(row,col))
Output (formatted as [row, column])
[0,2]
[1,2]
[2,1]
[3,3]
[4,1]
[4,3]
This could be turned into a function too
def findIndices(board, x):
l = []
for row in range(len(board)):
for col, value in enumerate(board[row]):
if value == x:
l.append([row,col])
return l
>>> findIndices(board, 'd')
[[0, 2], [1, 2], [2, 1], [3, 3], [4, 1], [4, 3]]
You need to enumerate both rows and columns. Using list comprehension it would look like this:
grid = """--d--
--d--
-d---
---d-
-d-d-""".splitlines()
print [ (i, [j for j, ch in enumerate(row) if ch == 'd'])
for i, row in enumerate(grid)]
# [(0, [2]), (1, [2]), (2, [1]), (3, [3]), (4, [1, 3])]
but this is a bit ugly, so you might extract inner comprehension into a function:
def get_dirties(row):
return [i for i, ch in enumerate(row) if ch == 'd']
all_dirties = [(i, get_dirties(row)) for row in enumerate(grid)]

Getting all the min elements and its indices from a list

I have a list that has a minimum element that is present multiple times like
a = [1,2,1,1,4,5,6]
And I want Python to return the element 1 and all the indices in the list where 1 is present. I tried using
min_index, min_value = min(enumerate(a), key=operator.itemgetter(1))
which gives only the index where 1 occurs first.
I'd just do it like this:
minimum = min(a)
indices = [i for i, v in enumerate(a) if v == minimum]
determine the minimum element, and then check it against other elements in the list.
def locate_min(a):
smallest = min(a)
return smallest, [index for index, element in enumerate(a)
if smallest == element]
which will return a tuple (min_element, [location, location, ...]). If I understand you correctly, this is what I think you want. For your example:
>>> locate_min([1, 2, 1, 1, 4, 5, 6])
(1, [0, 2, 3])
This example uses a list comprehension. If you're not familiar with this, it's roughly equivalent to the following for-loop version. (use the first version, this is just to help your understanding of how it works)
def locate_min(a):
min_indicies = []
smallest = min(a)
for index, element in enumerate(a):
if smallest == element: # check if this element is the minimum_value
min_indicies.append(index) # add the index to the list if it is
return smallest, min_indicies

Getting the indices of the X largest numbers in a list

Please no built-ins besides len() or range(). I'm studying for a final exam.
Here's an example of what I mean.
def find_numbers(x, lst):
lst = [3, 8, 1, 2, 0, 4, 8, 5]
find_numbers(3, lst) # this should return -> (1, 6, 7)
I tried this not fully....couldn't figure out the best way of going about it:
def find_K_highest(lst, k):
newlst = [0] * k
maxvalue = lst[0]
for i in range(len(lst)):
if lst[i] > maxvalue:
maxvalue = lst[i]
newlst[0] = i
Take the first 3 (x) numbers from the list. The minimum value for the maximum are these. In your case: 3, 8, 1. Their index is (0, 1, 2). Build pairs of them ((3,0), (8,1), (1,2)).
Now sort them by size of the maximum value: ((8,1), (3,0), (1,2)).
With this initial List, you can traverse the rest of the list recursively. Compare the smallest value (1, _) with the next element in the list (2, 3). If that is larger (it is), sort it into the list ((8,1), (3,0), (2,3)) and throw away the smallest.
In the beginning you have many changes in the top 3, but later on, they get rare. Of course you have to keep book about the last position (3, 4, 5, ...) too, when traversing.
An insertion sort for the top N elements should be pretty performant.
Here is a similar problem in Scala but without the need to report the indexes.
I dont know is it good to post a solution, but this seems to work:
def find_K_highest(lst, k):
# escape index error
if k>len(lst):
k=len(lst)
# the output array
idxs = [None]*k
to_watch = range(len(lst))
# do it k times
for i in range(k):
# guess that max value is at least at idx '0' of to_watch
to_del=0
idx = to_watch[to_del]
max_val = lst[idx]
# search through the list for bigger value and its index
for jj in range(len(to_watch)):
j=to_watch[jj]
val = lst[j]
# check that its bigger that previously finded max
if val > max_val:
idx = j
max_val = val
to_del=jj
# append it
idxs[i] = idx
del to_watch[to_del]
# return answer
return idxs
PS I tried to explain every line of code.
Can you use list methods? (e.g. append, sort, index?). If so, this should work (I think...)
def find_numbers(n,lst):
ll=lst[:]
ll.sort()
biggest=ll[-n:]
idx=[lst.index(i) for i in biggest] #This has the indices already, but we could have trouble if one of the numbers appeared twice
idx.sort()
#check for duplicates. Duplicates will always be next to each other since we sorted.
for i in range(1,len(idx)):
if(idx[i-1]==idx[i]):
idx[i]=idx[i]+lst[idx[i]+1:].index(lst[idx[i]]) #found a duplicate, chop up the input list and find the new index of that number
idx.sort()
return idx
lst = [3, 8, 1, 2, 0, 4, 8, 5]
print find_numbers(3, lst)
Dude. You have two ways you can go with this.
First way is to be clever. Phyc your teacher out. What she is looking for is recursion. You can write this with NO recursion and NO built in functions or methods:
#!/usr/bin/python
lst = [3, 8, 1, 2, 0, 4, 8, 5]
minval=-2**64
largest=[]
def enum(lst):
for i in range(len(lst)):
yield i,lst[i]
for x in range(3):
m=minval
m_index=None
for i,j in enum(lst):
if j>m:
m=j
m_index=i
if m_index:
largest=largest+[m_index]
lst[m_index]=minval
print largest
This works. It is clever. Take that teacher!!! BUT, you will get a C or lower...
OR -- you can be the teacher's pet. Write it the way she wants. You will need a recursive max of a list. The rest is easy!
def max_of_l(l):
if len(l) <= 1:
if not l:
raise ValueError("Max() arg is an empty sequence")
else:
return l[0]
else:
m = max_of_l(l[1:])
return m if m > l[0] else l[0]
print max_of_l([3, 8, 1, 2, 0, 4, 8, 5])

Categories