Counting near crosses in a given matrix

Question:

Imagine I am given a matrix, I need to count how many near crosses there are. A near cross is an extension of a normal cross, which means the same number across an entire row and an entire column of the matrix but the number at the intersection could be different. How should I approach finding crosses and then testing for near crosses?

Test Cases:

[[1, 1, 1, 1, 1],
 [2, 2, 1, 3, 3],
 [1, 2, 1, 2, 2],
 [5, 5, 1, 6, 6],
 [2, 2, 1, 1, 1]]

and

[[1, 1, 0, 1, 1],
 [0, 0, 1, 0, 0],
 [0, 0, 1, 0, 0],
 [0, 0, 1, 0, 0],
 [0, 0, 1, 0, 0]]

both have 1 near cross in them.

[[1, 1, 0, 1, 1],
 [0, 0, 1, 1, 0],
 [1, 1, 1, 0, 1], 
 [0, 0, 1, 1, 0],
 [0, 0, 1, 1, 0]]

has 2 near crosses.

Asked By: ViridTomb

||

Answers:

You could use Counter to identify which rows have at most one deviating value. This is true when one frequency is at least n-1, where n is the number of columns.

Then you could list the deviation point (coordinates), or all points on the row (when there is no deviating value). This gives a set of coordinates that each could be the crossing point of a near-cross.

Transpose the matrix and repeat the above filtering, and then mirror each of the resulting points (x vs. y)

As a result you’ll have two sets of potential crossing points. The intersection of these two sets will give the actual crossing points of near-crosses.

Here is an implementation of that algorithm:

from collections import Counter

def transpose(matrix):
    return [list(row) for row in zip(*matrix)]

def potentialcrosspoints(matrix):
    n = len(matrix[0])
    for i, row in enumerate(matrix):
        entries = list(Counter(row).items())
        if len(entries) == 1:
            for j in range(n):
                yield i, j, row[0]
        elif n - 1 in (entries[0][1], entries[1][1]):
            for j, entry in enumerate(entries):
                if entry[1] == 1:
                    yield i, row.index(entry[0]), entries[1 - j][0]

def mirrorpoints(points):
    return [(j, i, val) for i, j, val in points]

def countnearcrosses(matrix):
    return len(set(potentialcrosspoints(matrix)).intersection(
               mirrorpoints(potentialcrosspoints(transpose(matrix)))))

# Run of the last example in the question
matrix = [[1, 1, 0, 1, 1],
          [0, 0, 1, 1, 0],
          [1, 1, 1, 0, 1], 
          [0, 0, 1, 1, 0],
          [0, 0, 1, 1, 0]]
total = countnearcrosses(matrix)    
print(total)  # 2

# Example mentioned in comments
matrix = [[1, 0],
          [0, 1]]
total = countnearcrosses(matrix)    
print(total)  # 4
Answered By: trincot
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.