cancel
Showing results for 
Search instead for 
Did you mean: 

How to skip a loop in kdb?

jack2
New Contributor
I have something like the following 

myfirstrun:raze {[x]

L
: select from ....

if count[L] <= 20
   
continue
end


} peach vals;


And I am trying to add an if statement in there that would skip the particular entry in `vals` if the logical condition is met. 
`continue` works well in matlab, but, i am not sure of the corresponding syntax in kdb. Thank you.
4 REPLIES 4

SJT
Valued Contributor
If your intent is to continue until more than 20 records in L, then you want to keep appending records to L until your condition is met. That indicates the While iterator.

The While iterator repeatedly applies a unary function f to an initial state until some test t of the state passes. Your initial state would be (();vals) – an empty list and the values to work on. The function f will keep returning states until t applied to the latest state returns zero. Your solution is t f/(();vals) – but what are f and t?

q)f:{list:x 0; v:x 1; (list,select from... first v;1_ v)}
q)L:{20>count first x} f/ (();vals)
..


Function f splits its argument into two. The Apply operator . will do that for us.

f:{(x,select from... first y;1_ y)}.

You guessed peach to iterate, but a peach slave knows only what it has retrieved itself. So the simple answer is to iterate as above on a single thread, comforted by the knowledge that V4.0 primitives seek opportunities to multithread. If peach saves you a lot of time, you could process chunks of vals, with t applied after each chunk.

HTH
Stephen


Stephen Taylor | Librarian | Kx | +44 7713 400852 | stephen@kx.com


ikorkhov
New Contributor
If all you want is skip some `vals` (represented by `x` one at a time inside the function) if some condition is met then you can end the execution of `myfirstrun` early. Let's say `vals` is a list of symbols and `L: select from trade where sym=x` is a list of trades in a particular symbol.

myfirstrun:raze {[x]
  L
: select from ....
 
if[count[L] <= 20; :()]; // end early returning an empty list
 
// do whatever you intended to do with L
 
} peach vals;

SJT
Valued Contributor
If you want to exclude results that fail your test, you can get all of them and then apply the test. And peach is just fine for the iteration.

myfirstrun:raze{x where 20<count each x}{select from ... x}peach vals

Suppose, as Igor and Alvi do, that you want to abort some substantial processing on the result sets. Let us represent that as a function sp.

myfirstrun:raze{x where 20<count each x}{sp select from ... x}peach vals / choose when to apply sp!

You may find you can simply apply sp to the filtered results above:

myfirstrun:sp raze{x where 20<count each x}{select from ... x}peach vals

Perhaps it must be applied individually to the filtered results:

myfirstrun:raze sp each{x where 20<count each x}{select from ... x}peach vals

Worst case, it must be applied within your lambda. Many writers reserve the if control word for side effects, and the if[ ... ; :res] construction to returning error messages. Functional style would use Cond:

myfirstrun:raze{
  L:select from ... ;
  foo: ... ;
  $[count[L]<=20; sp[L;foo]; ()] } peach vals

Or use the Do iterator:

myfirstrun:raze{("j"$count[L]<=20) sp/L:select from ... x}peach vals

Here ("j"$count[L]<=20) returns an int 0 or 1, and the Do iterator applies sp that many times to L.


Stephen Taylor | Librarian | Kx | +44 7713 400852 | stephen@kx.com


alvi_kabir919
New Contributor II
You can filter out the items first, then apply your function over them and apply those values back into the vals list:

@[vals;i;:;] f peach vals i:where {20<count select from ...} peach vals

vals is your list
{20<count select from ...}is your filtering function that returns a boolean
i is your list of indices that have the function applied to them
f is your function to apply
@[vals;i;:;]is a projection of the apply function, here it assigns to i (indices) that values that are to the right of the projection

If you don't care about peach you can encapsulate the code in the apply function:

@[vals;where {20<count select from ...} each vals;f]

Here the function f gets applied to items of vals at the indices specified in the second argument