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.