How to find the last nonzero element in an array where zeros are sprinkled throughout?

Suppose I have a 1D wave that looks like:

{2,5,8,0,1,4,33,6,3,7,0,8,0,3,1,8,99,0,0,0,0,0,0,0,0}

I want to find the index of 99, which of course won't always be 99. It's just the last nonzero value before a trail of zeroes. I have hundreds of these waves and the last nonzero value is in a different place each time. The waves are also different lengths.

In Python, I would write

idx = numpy.max(numpy.nonzero(wave))

Or, without numpy:

idx = [index for index, item in enumerate(wave) if item != 0][-1]

But Igor doesn't have anything so elegant. Do I have to make a new reversed wave, then search element-by-element until I find something nonzero, then figure out what the non-reversed index is?

Hi,

One approach

replace 0 with nans, zapnans, read last value.

matrix temp=replace(0,wave,Nan)
wave transform zapnans temp
lastvalue =temp[numpnts(temp)-1]

Alternative

loop from the end

variable i
for(i=numpnts(wave)-1;i<=0;i-=1)
   if(!wave[i]
     break
   endif
endfor

then the value is wave[i] and the point where that occurs is i

Andy

Hmm... somehow Andy's code is very broken today. Here is how this should look:

function lastNonZero1(wave input)
    MatrixOp/Free temp=replace(input,0,Nan)
    WaveTransform zapnans temp
    variable lastvalue=temp[numpnts(temp)-1]
    FindValue/R/V=(lastvalue) input
    return V_value
end

function lastNonZero2(wave input)
    int i=numpnts(input)-1
    for(;i>=0;i-=1)
       if(input[i])
         break
       endif
    endfor
    return i
end

Try:

print lastnonzero1(mywave)
  16
print lastnonzero2(mywave)
  16

 

Here is another solution that works with your data:

Function Demo()
    Make/O test = {2,5,8,0,1,4,33,6,3,7,0,8,0,3,1,8,99,0,0,0,0,0,0,0,0}
    Reverse test; FindLevel/P/Q test, 0; Reverse test;
    int point = numpnts(test)-V_LevelX-1
    point -= 1  // -1 added 2024-10-01
    Print point
End

 

Here is another solution that eliminates the need for Reverse using /R with swap parameters:

Function Demo()
    Make/O test = {2,5,8,0,1,4,33,6,3,7,0,8,0,3,1,8,99,0,0,0,0,0,0,0,0}
    int numPoints = numpnts(test)
    FindLevel/P/Q/R=(numPoints-1,0) test, 0
    int point = V_LevelX - 1  // -1 added 2024-10-01
    Print point
End

 

... or you can use MatrixOP:

The index of the last non-zero element of the wave ddd is:

MatrixOP/o/p=1 aa=maxval(IndexRows(ddd)*(1-equal(ddd,0)))

The data at that wave point is:

print ddd[aa[0]]

 

I think that you need to subtract one from the index in hrodstein's solutions if you want to find the last non-zero point.

You can construct for yourself an equivalent to numpy's nonzero:

function/wave nonzero(wave w)
    MatrixOP/free wOut = zapINFs(indexRows(w)/(1-equal(w,0)))
    return wOut
end

 

Here's yet another solution. It may be that Extract does more work than necessary, but it's simple and easy to understand:

Function LastNonZero(Wave source)

    Extract/INDX/FREE source, nonzeroIndex, source != 0
    return nonzeroIndex[inf]
end

 

I think that you need to subtract one from the index in hrodstein's solutions if you want to find the last non-zero point.

Tony is right. My solutions found the last zero value. I have corrected them. Thanks Tony.