Search code examples
kdb

q/Kdb+ Vector Conditional to update and iterate over rows in a column of a table


I am trying to update a column in my table using the vector conditional function in kdb+ such that after each conditional is tested, the value outputted is based on the output value previous in the row above but same column. Suppose I have a table as such:

t:([] number:-100 100 600 -200 -400f);
t: update cumsum: sums[number] from t;
t: update signumcumsum: signum cumsum from t;
t: update role:1b from t;
number cumsum signumcumsum
-100 -100 -1
100 0 0
600 600 +1
-200 400 +1
-400 0 0

And now I would like to use a vector conditional to update each role such that each value is based on the previous value in the row above. My command is

t: update role: ?[(signumcumsum)=(prev signumcumsum);1^prev role;not 1^prev role] from t;

And I intend the table to look like this

number cumsum signumcumsum role
-100 -100 -1 1b
100 0 0 0b
600 600 +1 1b
-200 400 +1 1b
-400 0 0 0b

However the table outputted in the console is like this:

number cumsum signumcumsum role
-100 -100 -1 1b
100 0 0 1b
600 600 +1 1b
-200 400 +1 1b
-400 0 0 1b

Is there something wrong with my logic or how I am writing the code? Would much appreciate any corrections or advice.


Solution

  • Potentially there are 2 issues with your logic.

    1. Using prev on a Boolean list gives 0b for the first element, not a null value. You are trying to fill a null value, but there are none.
    2. The previous role value is not carrying forward like you expect.

    I can get the expected output by fixing point 2. Here I used scan \ to continually modify the role value, which starts as 1b. This carries the previous role value forward.

    q)update role:{[role;signumcumsum;prevSCS]$[signumcumsum=prevSCS;role;not role]}\[1b;signumcumsum;prev[first signumcumsum;signumcumsum]] from t
    number cumsum signumcumsum role
    -------------------------------
    -100   -100   -1           1
    100    0      0            0
    600    600    1            1
    -200   400    1            1
    -400   0      0            0
    

    Note the use of prev[first signumcumsum;signumcumsum] here which ensures the initial role value is 1b.