Search code examples
kdb

Reliably parsing/applying a function to tables vs dictionaries in kdb


I am trying to do a functional select within a function in q as follows:

dosel:{[tab] ?[tab;enlist(>;`scalar;5);0b;()]};

which works perfectly on tabular input i.e.

q)tab:([]time:2#.z.z;tag:0 0;direction:0 0;scalar:5 10)
q)count tab
2
q).Q.s1 tab
"+`time`tag`direction`scalar!(2020.12.23T12:28:08.254 2020.12.23T12:28:08.254;0 0;0 0;5 10)"
q)dosel tab
time                    tag direction scalar
--------------------------------------------
2020.12.23T12:49:19.885 0   0         10

And, as expected, doesn't work on dictionary tables:

q)tab:`time`tag`direction`scalar!(.z.z;0;0;4)
q)count tab
4
q)dosel tab
'type
  [1]  dosel:{[tab] ?[tab;enlist(>;`scalar;5);0b;()]}
                ^

You could fix this by using enlist i.e.

q))dosel enlist tab
time tag direction scalar
-------------------------

However this has obvious edge cases i.e.

q)tab:`time`tag`direction`scalar!(2#.z.z;2#0;2#0;2#4)
q))type tab
99h
q)count tab
4
q).Q.s1 tab
"`time`tag`direction`scalar!(2020.12.23T12:55:48.835 2020.12.23T12:55:48.835;0 0;0 0;4 4)"
q)dosel tab
'type
  [1]  dosel:{[tab] ?[tab;enlist(>;`scalar;5);0b;()]}
                    ^
q)dosel enlist tab
'type
  [4]  dosel:{[tab] ?[tab;enlist(>;`scalar;5);0b;()]}
                    ^
q)dosel flip tab
'type
  [7]  dosel:{[tab] ?[tab;enlist(>;`scalar;5);0b;()]}
                    ^

One can see in the above example that count would not be a good approximation of the tabular nature therin. How does one reliably parse tabular/dictionary data to their appropriate form such that dosel can be applied.

Apologies if this is a newbie question... thanks again.


Solution

  • Your last example works for me, I'm not sure why you're seeing an error:

    q)tab:`time`tag`direction`scalar!(2#.z.z;2#0;2#0;2#4)
    q)
    q)dosel flip tab
    time tag direction scalar
    -------------------------
    

    Either way - your function is designed to work on a table so you need to ensure your input is always a table. This could be achieved using:

    makeTab:{$[98h=type x;x;@[(flip;enlist)0>type first x;x]]};
    
    q)dosel makeTab ([]time:2#.z.z;tag:0 0;direction:0 0;scalar:5 10)
    time                    tag direction scalar
    --------------------------------------------
    2020.12.23T13:18:58.909 0   0         10
    q)
    q)dosel makeTab `time`tag`direction`scalar!(.z.z;0;0;4)
    time tag direction scalar
    -------------------------
    q)
    q)dosel makeTab `time`tag`direction`scalar!(2#.z.z;2#0;2#0;2#4)
    time tag direction scalar
    -------------------------
    

    This makeTab function assumes you'll pass in a table or dictionary but it can be generalised further if needed (e.g. keyed tables)