find pattern in matrix made of lists python 3

为君一笑 提交于 2021-02-08 11:55:56

问题


I have a list made of lists, to create a matrix, mostly filled with zeros and some other numbers like this

a = [[0,0,0,1,0,0,0,0],
     [3,0,0,2,1,0,0,0],
     [3,0,0,0,0,1,0,0],
     [3,5,0,4,0,0,0,0]]

how could I make a function that takes that variable, and find if there is a number repeated 3 times in the diagonals?

For example that It returns True because of the 1. I tried to implement a function like this:

def find_diagonal(matriz):
    for x in range(len(matrix)):
        for for a in range(len(x)):
            if matriz[x][a] != 0:
                encontrar = matriz[x][a]
                if matriz[x+1][a-1] == encontrar:
                    if matriz[x+2][a-2] == encontrar:
                        return True

and repeat the conditions after the if matriz[x][a] != 0 with the other diagonals (this one looks for the ones directing southwest).

But besides from not working with every example (sometimes it works once, and stops working with the same example), and at the edges always raises index errors because the list checks for rows over the top.


回答1:


As @ShadowRanger pointed out it's probably easier to use a flattened list and use slicing with a step that's +/- 1 of the rowlen (this gives you the items that are diagonal):

def has_diagonals(listoflist, n=3):
    rowlen = len(listoflist[0])
    numrows = len(listoflist)
    l = [i for row in listoflist for i in row]
    for rownr in range(numrows + 1 - n):
        # Diagonals to the lower right
        for start in range(rowlen + 1 - n):
            lr_diag = l[start+rownr*rowlen::rowlen+1][:n]
            print(lr_diag)
            first = lr_diag[0]
            if first == 0:  # don't check for zero-diagonals
                continue
            if all(item == first for item in lr_diag):  # are all items equal
                print('match', lr_diag)

        # Diagonals to the lower left   
        for start in range(n - 1, rowlen):
            rl_diag = l[start+rownr*rowlen::rowlen-1][:n]
            print(rl_diag)
            first = rl_diag[0]
            if first == 0:  # don't check for zero-diagonals
                continue
            if all(item == first for item in rl_diag):  # are all items equal
                print('match', rl_diag)

I included some print-calls that I used to visualize the inner workings, I think these might help you to understand what is happening. The prints with 'match' should be replaced by a return True or whatever you want the function to return.

It's possible to make this more efficient, but it should be correct (at least for your a-matrix)




回答2:


How about this:

def check_diag(a, y, x):
  """Take a[y][x] and check if it starts a diagonal"""
  result = False

  # We search downwards, there should be at least 2 more rows
  if y > len(a)-2:
    return False

  if x < len(a[y])-2:
      # Searching SE direction if possible
      result |= (a[y][x] == a[y+1][x+1] == a[y+2][x+2])
  if x > 1:
      # Searching SW direction if possible
      result |= (a[y][x] == a[y+1][x-1] == a[y+2][x-2])

  return result

def has_diag(a):
  # Take all non-zero elements and check if they meet the diag condition
  return any([check_diag(a,y,x)
                for y in range(len(a))
                for x in range(len(a[y]))
                if a[y][x]])

This will also find longer diagonals, not sure if you want that.


Edit: more "brutal" version with less indexing magic:

def check_diag2(a, y, x):
  """Take a[y][x] and check if it starts a diagonal"""
  try:
    if (a[y][x] == a[y+1][x+1] == a[y+2][x+2]):
      return True
  except IndexError:
    pass

  try:
    if (a[y][x] == a[y+1][x-1] == a[y+2][x-2]):
      return True
  except IndexError:
    pass

  return False


来源:https://stackoverflow.com/questions/44013618/find-pattern-in-matrix-made-of-lists-python-3

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!