Pratham Patel
Pratham Patel

Reputation: 27

Finding a change in a row of a matrix in python

I have a NxM matrix encoded in 0s and 1s - where only the 1s are to be printed in its respective locations whereas the 0s are blank spaces, such as the following matrix:

 m = [[0 0 0 0 0 0 0 1 1 1 1 0 0 0 0 0 0 0 0 0]
      [0 0 0 0 0 0 0 1 1 1 1 0 0 0 0 0 0 0 0 0]
      [0 0 0 0 0 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0]
      [0 0 0 0 0 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0]
      [0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 0 0]
      [0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 0 0]
      [1 1 1 1 0 0 0 0 1 1 1 1 1 1 0 0 0 0 1 1]

My question is how can I create a starting point from the change that takes place from a 0 to a 1 and an end point from the change that takes place from a 1 to a 0 in each row. Then print all the 1s between the start point and end point

I have the following code (which does not work):

nrows, ncols = m.shape #gets the shape of the matrix
for r in range(nrows):
  for c in range(ncols):
    if m[r,c] == 0 and m[r,c+1] == 1: #checks if there is a 0 first and then a 1 in the next index of the column in the row to create a starting point
       start = m[r,c+1]
    if m[r,c] == 1 and m[r,c+1] == 0: #checks if there is a 1 first and then a 0 in the next index of the column in the row to create an end point
       end = m[r, c+1]

My desired output is, for example taking the lastrow into consideration:

It should print everything between the first 1 and last 1 before a 0 is found in that row, excluding the 0s. So basically this: 1 1 1 1....1 1 1 1 1 1....1 1 The dots (.)represent the 0s that have to be excluded All help and advice will be highly appreciated.

Upvotes: 1

Views: 293

Answers (3)

cdlane
cdlane

Reputation: 41872

Is your goal the printed output or is your goal the markers that indicate where 1's begin and end? If your goal is just the printed output, why not something simple like:

m = [[0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0],
     [0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0],
     [0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
     [0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
     [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0],
     [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0],
     [1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1]
]

for row in m:
    for bit in row:
        print(bit or ' ', end=' ')
    print()

OUTPUT

              1 1 1 1                   
              1 1 1 1                   
          1 1 1 1                       
          1 1 1 1                       
                            1 1 1 1     
                            1 1 1 1     
1 1 1 1         1 1 1 1 1 1         1 1 

Manipulate as you see fit to eliminate the spaces for the zeros or spaces between the 1's (i.e. ' ' space vs. '' empty string.)

Do you mind showing/explaining on how I am able to get the markers where the 1s begin and end?

Borrowing from an SO answer to Identify groups of continuous numbers in a list, we can do:

for row in m:
    indicies = compress(count(), row)

    ranges = []

    for _, g in groupby(enumerate(indicies), lambda x: x[0] - x[1]):
        group = [x[1] for x in g]
        ranges.append((group[0], group[-1]))

    print(ranges)

OUTPUT

[(7, 10)]
[(7, 10)]
[(5, 8)]
[(5, 8)]
[(14, 17)]
[(14, 17)]
[(0, 3), (8, 13), (18, 19)]

Upvotes: 1

Jared Goguen
Jared Goguen

Reputation: 9010

Here's a straight forward way of getting the successive differences into a new array.

coded = np.append(m[:,:1]*2-1, m[:,1:] - m[:,:-1], axis=1)
# [[-1  0  0  0  0  0  0  1  0  0  0 -1  0  0  0  0  0  0  0  0]
#  [-1  0  0  0  0  0  0  1  0  0  0 -1  0  0  0  0  0  0  0  0]
#  [-1  0  0  0  0  1  0  0  0 -1  0  0  0  0  0  0  0  0  0  0]
#  [-1  0  0  0  0  1  0  0  0 -1  0  0  0  0  0  0  0  0  0  0]
#  [-1  0  0  0  0  0  0  0  0  0  0  0  0  0  1  0  0  0 -1  0]
#  [-1  0  0  0  0  0  0  0  0  0  0  0  0  0  1  0  0  0 -1  0]
#  [ 1  0  0  0 -1  0  0  0  1  0  0  0  0  0 -1  0  0  0  1  0]]

In this array, a -1 indicates the start of a spree of 0's, and a 1 indicates the start of a spree of 1's. I'm not exactly clear on what you're trying to do, but maybe this will help.

Upvotes: 0

Prune
Prune

Reputation: 77857

You haven't given a viable MCVE yet; I converted this to Python and made a solution.

You take each row, shift it left one position, and subtract from the original. This will mark all transitions with 1 and -1. Then you just need to find the first 0=>1 change, and then the 1=>0 change after that. Adjust the indices as you see fit.

Note: I kept this low-tech. The solution can be greatly shortened if you convert the lists to bitmaps, find transitions with XOR, and be careful about marking the starting value (if it starts with 1, then you need the 2nd & 3rd transitions, not the first two).

m = [[0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0],
     [0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0],
     [0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
     [0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
     [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0],
     [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0],
     [1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1]
]

for row in range(len(m)):
    line = m[row]
    first = line[:-1]
    shift = line[1:]

    diff = [first[i] - shift[i] for i in range(len(first))]
    l_bound = diff.index(-1) + 1
    r_bound = diff[l_bound:].index(1) + l_bound
    print
    print row, '\t', line
    print '\t', diff
    print '\t', l_bound, r_bound

Output:

0   [0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0]
    [0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0]
    7 10

1   [0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0]
    [0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0]
    7 10

2   [0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
    [0, 0, 0, 0, -1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
    5 8

3   [0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
    [0, 0, 0, 0, -1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
    5 8

4   [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0]
    [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 1, 0]
    14 17

5   [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0]
    [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 1, 0]
    14 17

6   [1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1]
    [0, 0, 0, 1, 0, 0, 0, -1, 0, 0, 0, 0, 0, 1, 0, 0, 0, -1, 0]
    8 13

Upvotes: 0

Related Questions