user9646441
user9646441

Reputation:

How can I interrupt a 'loop' in kdb?

numb is a list of numbers:

q))input
42 58 74 51 63 23 41 40 43 16 64 29 35 37 30 3  34 33 25 14 4  39 66 49 69 13..

31 41 39 27 9  21 7  25 34 52 60 13 43 71 10 42 19 30 46 50 17 33 44 28 3  62..

15 57 4  55 3  28 14 21 35 29 52 1  50 10 39 70 43 53 46 68 40 27 13 69 20 49..

3  34 11 53 6  5  48 51 39 75 44 32 43 23 30 15 19 62 64 69 38 29 22 70 28 40..

18 30 60 56 12 3  47 46 63 19 59 34 69 65 26 61 50 67 8  71 70 44 39 16 29 45..

I want to iterate through each row and calculate the sum of the first 2 and then 3 and then 4 numbers etc. If that sum is greater than 1000 I want to stop the iteration on that particualr row and jump on the next row and do the same thing. This is my code:

{[input]
 tot::tot+{[x;y]
   if[1000<sum x;:count x;x,y]
  }/[input;input]
 }each numb 

My problem here is that after the count of x is added to tot the over keeps going on the same row. How can I exit over and jump on the next row?

UPDATE: (QUESTION STILL OPEN) I do appreciate all the answers so far but I am not looking for an efficient way to sum the first n numbers. My question is how do I break the over and jump on the next line. I would like to achieve the same thing as with those small scripts:

C++

for (int i = 0; i <= 100; i++) {
if (i = 50) { printf("for loop exited at: %i ", i); break; }
}

Python

for i in range(100):
  if i == 50:
      print(i);
      break;

R

for(i in 1:100){
  if(i == 50){
    print(i)
    break
  }
}

Upvotes: 1

Views: 1712

Answers (4)

terrylynch
terrylynch

Reputation: 13572

Kdb does have a "stop loop" mechanism but only in the case of a monadic function with single seed value

/keep squaring until number is no longer less than 1000, starting at 2
q){x*x}/[{x<1000};2]
65536

/keep dealing random numbers under 20 until you get an 18 (seed value 0 is irrelevant)
q){first 1?20}\[18<>;0]
0 19 17 12 15 10 18

However this doesn't really fit your use case and as other people have pointed out, this is not how you would/should solve this problem in kdb.

Upvotes: 0

emc211
emc211

Reputation: 1379

You can use while loops in KDB although all KDB developers are generally too afraid of being openly mocked and laughed at for doing so

q){i:0;while[i<>50;i+:1];:"loop exited at ",string i}`
"loop exited at 50"

Upvotes: 1

emc211
emc211

Reputation: 1379

You could use coverage in this case to exit when you fail to satisfy a condition https://code.kx.com/q/ref/adverbs/#converge-repeat

The first parameter would be a function that does your check based on the current value of x which will be the next value to be passed in the main function.

For your example ive made a projection using the main input line then increase the indexes of what i am summing each time:

q)numb
98 11 42 97 89 80 73 35 4  30
86 33 38 86 26 15 83 71 21 22
23 43 41 80 56 11 22 28 47 57
q){[input] {x+1}/[{100>sum (y+1)#x}[input;];0] }each numb
1 1 2

this returns the first index of each where running sum is over 100

However this isn't really an ideal use case of KDB could instead be done with something like

(sums@/:numb) binr\: 100

maybe your real example makes more sense

Upvotes: 1

Mark Kelly
Mark Kelly

Reputation: 1780

I think this is what you are trying to accomplish.

sum {(x & sums y) ? x}[1000] each input

It takes a cumulative sum of each row and takes an element wise minimum between that sum and the input limit thereby capping the output at the limit like so:

q)(100 & sums 40 43 16 64 29)
40 83 99 100 100

It then uses the ? operator to find the first occurance of that limit (i.e the element where this limit was equaled or passed) adding one as it is 0 indexed. In the example the first 100 occurs after 3 elements. You might want add one to include the first element after the limit in the count.

q)40 83 99 100 100 ? 100
3

And then it sums this count over all rows of the input.

Upvotes: 1

Related Questions