remove some elements from a matrix according to the indices

Viewed 289

I have a matrix:

a = ([[1, 0, 0, 0],
       [0, 0, 1, 1],
       [0, 1, 0, 1]
       [1, 0, 0, 1]])

and I want to print the 0s in the matrix but not all of the 0s. I only want to keep the 0s in every row with the smallest index and remove all subsequent zeros in the row. For instance, in the first row of this matrix, the second element (a[0][1]) should be kept and the rest of elements in the first row should be deleted since they are all zeros.

I used pop() for 2D array but I got attribute error. And the output is not correct too. I don't know how to compare indices and select the smallest column index in every row.

This is my code:

for ix, row in enumerate(a):
  for iy, i in enumerate(row):
    if i==0 and (iy+ix<(iy+1)+ix) :
        a[ix].pop((iy+1))
        print(ix,iy)
    elif i==0 and (iy+ix>(iy+1)+ix):
        a[ix].pop(iy)
        print(ix,iy+1)
print(a)

my expected result is the set of indices and the modified matrix a.

0 1

1 0

2 0

3 1

a=[[1,0],[0,1,1],[0,1,1],[1,0]]

Could anyone help me?

4 Answers

try this:

a = [[1, 0, 0, 0],
       [0, 0, 1, 1],
       [0, 1, 0, 1],
       [1, 0, 0, 1]]

b = []
for i in a:
    f = False
    c = []
    for j in i:
        if (j==0 and f==False) or j != 0:
            c.append(j)
            if j == 0: f = True
        else:
            continue
    b.append(c)

output:

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

For getting indices zero in array you can try this:

list({i : j.index(0) for i,j in enumerate(b)}.items())
# [(0, 1), (1, 0), (2, 0), (3, 1)]

Looking at your example input

a = [[1,0,0,0],[0,0,1,1],[0,1,0,1],[1,0,0,1]]

and the expected output >>[(0, 1), (1, 0), (2, 0), (3, 1)]

you can reframe the problem as finding the index of the element in each row which has the value zero (and where more than one element exists, return the first).

By framing it this way, the solution is as simple as iterating through each row of a and retrieving the index of the value 0 (whereby only the first element will be returned by default).

Using list comprehension that would look like this:

value_to_find = 0
desired_indexes = [
  row.index(value_to_find) for row in a
]

or using map that would be:

value_to_find = 0
desired_indexes = map(lambda row:row.index(value_to_find), a)

Then you could enumerate them to pair the results with the row number

enumerate(desired_indexes)

Et voila! >>[(0, 1), (1, 0), (2, 0), (3, 1)]

The entire solution can be written in a single line like so:

answer = list(enumerate(map(lambda row:row.index(0), a)))

Assuming there's a zero in every row, you can get its column index with

c = np.argmin(a, axis=1)

Alternatively, if the matrix can contain negative numbers, you can do

c = np.argmax(np.equal(a, 0), axis=1)

The rows are just

r = np.arange(len(a))

The result you want is then

result = np.stack((r, c), axis=-1)

If there are rows without a zero in them, you can filter the result with a mask:

mask = np.array(a)[r, c] == 0
result = result[mask, :]

This solution only works if there is at least one zero in every row.

indices = []
for x,row in enumerate(a):
    i = row.index(0)
    indices.append((x,i))
    a[x] = row[:i+1] + [e for e in row[i:] if e]

print(indices)
print(a)

Output

[(0, 1), (1, 0), (2, 0), (3, 1)]
[[1, 0], [0, 1, 1], [0, 1, 1], [1, 0, 1]]
Related