Home > FAQ > Data Manipulation > Event histories (status histories) > Cleaning or editing an event history > Find the first/last start/stop event

Find the first/last start/stop event

For purposes of this discussion, we are assuming the event history is stored in a coded effective date array called EventHistory, where the start event codes are 10, 11, and 12, and the stop event codes are 31, 41, 51, and 61. We also assume that the first 2 lines of the expressions are (so EV_DT and Code are available):

EV_DT:= #START EventHistory & ; the event date for each event in EventHistory
Code:= #VALUE EventHistory & ; the code for each event in EventHistory

How to find the last event code, the last stop event code, or the last start event code:

If we're looking for the last event, and we don't have any zero event codes, then this is very easy because #GETVALUE always returns the last non-zero value in an array:

LastCode:= #GETVALUE Code & ; always finds the last non-zero value in Code

If we were looking for the last event, and we have zero event codes, then this is only slightly harder because we can use the left argument to #GETVALUE to indicate which value in the right argument (e.g., Code) we want:

B:= Code > -1 & ; most people don't use negative codes, so B contains a 1 for every value in Code
LastCode:= B #GETVALUE Code &
; First, #GETVALUE finds the last non-zero value in B (it's always the last value because B only
; contains 1's), and then it grabs the corresponding value in Code (the last value in Code).
; Without a left argument, #GETVALUE Code returns the last non-zero value in Code, which is not
; what we want if Code contains a zero code.

If we're looking for the last start event, we can use the left argument to #GETVALUE to indicate which value in the right argument (e.g., Code) we want:

IsStartEvent:= Code #IN (10, 11, 12) & ; #IN should list every start event code
; IsStartEvent will contain only 1's at start events, 0's at all other events

LastCode:= IsStartEvent #GETVALUE Code &
; First, #GETVALUE finds the last non-zero value in IsStartEvent, 
; then it grabs the corresponding value in Code (the last start value in Code).

; If there aren't any start events (i.e., IsStartEvent is all 0's)? Then IsStartEvent #GETVALUE Code
; will return a zero! If you are using a zero start event code, then you'll need to use
; (0=#GETVALUE IsStartEvent) to determine if there were no start
 events.

If we're looking for the last stop event, we can use the left argument to #GETVALUE to indicate which value in the right argument (e.g., Code) we want:

IsStopEvent:= Code #IN (31, 41, 51, 61) & ; #IN should list every stop event code
;IsStopEvent will contain only 1's at stop events, 0's at all other events

LastCode:= IsStopEvent #GETVALUE Code &
; First, #GETVALUE finds the last non-zero value in IsStopEvent, 
; then it grabs the corresponding value in Code (the last stop value in Code). 

; If there aren't any stop events (i.e., IsStopEvent is all 0's)? Then IsStopEvent #GETVALUE Code
; will return a zero! If you are using a zero stop event code, then you need to use
; (0=#GETVALUE IsStopEvent) to determine if there were no stop events.
; NOTE: To make this work correctly, we often need to add the final decrement date (if it's not there).

How to find the first event code, the first start event code, or the first stop event code:

If we're looking for the first event code, we can use the left argument to #GETVALUE to indicate which value in the right argument (e.g., Code) we want:

B:= 0=('P' #GETASOF EV_DT) &
; First, using 'P' #GETASOF will get the previous value of each value of EV_DT. The previous date 
; of the first date in EV_DT doesn't exist, so only the first value of('P' GETASOF EV_DT) is a zero.  

; Then, the first value in B is a 1, everywhere else it's 0.

FirstCode:= B #GETVALUE Code &
; First, #GETVALUE finds the last non-zero value in B (the first value in B is 1, everywhere
; else it's 0), and then it grabs the corresponding value in Code (the first value in Code).

Looking for the first start event code, when the first code is NOT guaranteed to be a start event, requires a little more work:

IsStartEvent:= Code #IN (10, 11, 12) & ; #IN should list every start event code
A:= 0 #MPSUM IsStartEvent &               ; (1)
B:= (A = 1) #AND [0 = ('P' #GETASOF A)] & ; (2)
FirstStartCode:= B #GETVALUE Code &
; First, #GETVALUE finds the last non-zero value in B (only one 1 at the first start event),
; and then it grabs the corresponding value in Code (the first start value in Code). 
; But, what if there aren't any start events (i.e., B is empty or it's all 0's)? 
; Then, B #GETVALUE Code will return a zero! If you are using a zero start event code, then 
; you'll need to use (0=#GETVALUE B) to determine if there were no start events.

 
; (1) IsStartEvent contains 0's (for every stop event) and 1's (for every start event),
;     something like 1 0 1 0 1 or 0 1 0 1 0 1. By using 0 #MPSUM, we calculate something
;     like 1 1 2 2 3 or 0 1 1 2 2 3. (It will be 0 0 0 0 0 if there are no start events.)
; (2) If the first event is a start event, then [0 = ('P' #GETASOF A)] finds the first event
;     because the previous value of the first value is always zero (and all the other previous
;     values are 1, 2, 3, 4,...). If the first start event is preceded by a stop event, then
;     [0 = ('P' #GETASOF A)] finds two events: the very first event and the first start event
;     (because it's been preceded by a stop event, i.e., a zero). Now, the (A = 1) #AND
;     ensures we always find the first start event (if there are any start events).

 

We could modify this expression to find the second, third, ... start events by changing (A=1) #AND [0 = ('P' #GETASOF A)] to (A=1) #AND [2 = ('P' #GETASOF A)] , or (A=2) #AND 1= ('P' #GETASOF A)], ... (if those events exist).

If we are looking for the first stop event code, then we can use the previous expression for "Looking for the first start event code", and only change the first 2 lines for stop events:

IsStopEvent:= Code #IN (31, 41, 51, 61) & ; #IN should list every stop event code
A:= 0 #MPSUM IsStopEvent &                ; (1)

Of course the comments on the expression would have to be changed too (because we are now looking for the first stop event, not the first start event).