delita
delita

Reputation: 1591

Processing each row in kdb table and appending arbitrary results in a new table

I have a table

t:([]a:`a`b`c;b:1 2 3;c:`x`y`z)

I would like to iterate and process each row. The thing is that the processing logic for each row may result in arbitrary lines of data, after the full iteration the result maybe as such e.g.

results:([]a:`a1`b1`b2`b3`c1`c2;x:1 2 2 2 3 3)

I have the following idea so far but doesn't seem to work:

uj { // some processing function } each t

But how does one return arbitrary number of data append the results into a new table?

Upvotes: 0

Views: 1314

Answers (5)

Alex R.
Alex R.

Reputation: 721

If I understand correctly your question you need something like this : (uj/){}each t

Check this bit :

(uj/)enlist[t],{x:update x:i from?[rand[20]#enlist x;();0b;{x!x}rand[4]#cols[x]];{(x;![x;();0b;(enlist`a)!enlist($;enlist`;((';{raze string(x;y)});`a;`i))])[y~`a]}/[x;cols x]}each t

This part :

x:update x:i from
   // functional form of a function that takes random rows/columns
   ?[rand[20]#enlist x;();0b;{x!x}rand[4]#cols[x]];
// some for of if-else and an update to generate column a (not bullet proof)
{(x;![x;();0b;(enlist`a)!enlist($;enlist`;((';{raze string(x;y)});`a;`i))])[y~`a]}/[x;cols x]

Basically the above gives something like :

q){x:update x:i from?[rand[20]#enlist x;();0b;{x!x}rand[4]#cols[x]];{(x;![x;();0b;(enlist`a)!enlist($;enlist`;((';{raze string(x;y)});`a;`i))])[y~`a]}/[x;cols x]}each t
+`a`b`c`x!(`a0`a1`a2`a3`a4`a5`a6`a7;1 1 1 1 1 1 1 1;`x`x`x`x`x`x`x`x;0 1 2 3 ..
+`a`x!(`a0`a1`a2`a3`a4`a5;0 1 2 3 4 5)
+`a`b`c`x!(`a0`a1`a2;1 1 1;`x`x`x;0 1 2)
+`a`b`c`x!(`a0`a1`a2`a3`a4`a5`a6`a7`a8`a9`a10`a11;1 1 1 1 1 1 1 1 1 1 1 1;`x`..

or taking the first one :

q)first{x:update x:i from?[rand[20]#enlist x;();0b;{x!x}rand[4]#cols[x]];{(x;![x;();0b;(enlist`a)!enlist($;enlist`;((';{raze string(x;y)});`a;`i))])[y~`a]}/[x;cols x]}each t
a   b x 
--------
a0  1 0 
a1  1 1 
a2  1 2 
a3  1 3 
a4  1 4 
a5  1 5 
a6  1 6 
a7  1 7 
a8  1 8 
a9  1 9 
a10 1 10

You can do (uj/)enist[t],{ // some function }each t to get what you want. Drop the enlist[t] if you don't want the table you start with in your result

Hope this helps.

Upvotes: 1

SJT
SJT

Reputation: 1097

Your best answer will depend very much on how you want to use the results computed from each row of t. It might suit you to normalise t; it might not. The key point here:

A table cell can be any q data structure.

The minimum you can do in this regard is to store the result of your processing function in a new column.

Below, an arbitrary binary function f returns its result as a dictionary.

q)f:{n:1+rand 3;(`$string[x],/:"123" til n)!n#y}
q)f [`a;2]
a1| 2
a2| 2

q)update d:a f'b from t
a b c d
---------------------
a 1 x `a1`a2`a3!1 1 1
b 2 y (,`b1)!,2
c 3 z `c1`c2!3 3

But its result could be any q data structure.

You were considering a unary processing function:

q)pf:{@[x;`d;:;] f . x`a`b}
q)pf each t
a b c d
---------------------
a 1 x `a1`a2`a3!1 1 1
b 2 y `b1`b2!2 2
c 3 z `c1`c2`c3!3 3 3

You might find other suggestions at KX Community.

Upvotes: 2

Matt Moore
Matt Moore

Reputation: 2800

If your processing function is outputting tables that conform, just raze should suffice:

raze {y#enlist x}'[t;1 3 2]
a b c
-----
a 1 x
b 2 y
b 2 y
b 2 y
c 3 z
c 3 z

Otherwise use (uj/)

(uj/) {y#enlist x}'[t;1 3 2]
a b c
-----
a 1 x
b 2 y
b 2 y
b 2 y
c 3 z
c 3 z

Upvotes: 2

Disastron
Disastron

Reputation: 437

Assuming you are using something from the table entries to indicate your arbitrary value, you can use a dictionary to indicate a number (or a function) which can be used to apply these values.

In this example, I use the c column of the original table to indicate the number of rows to return (and the number from 1 to count to). As each entry of the table is a dictionary, I can index using the column names to get the values and build a new table. I also use raze to join each of the results together, as they will each have the same schema.

raze {[x]
  d:`x`y`z!1 3 2;
  ([]a:((),`$string[x[`a]],/:string 1+til d[x[`c]]);x:((),d[x[`c]])#x[`b])
 } each t

Upvotes: 3

Maurice Lim
Maurice Lim

Reputation: 918

Not sure if this is what you want, but you can try something like this:

ungroup select a:`${y,/:x}[string b]'[string a],b from t

Or you can use accumulators if you need the result of the previous row calculations like this:

{y[`b]+:last[x]`b;x,y}/[t;t]

Upvotes: 2

Related Questions