Search code examples
kdb

kdb+: function with two arguments from columns


I have a function that does something with a date and a function that takes two arguments to perform a calculation. For now let's assume that they look as follows:

d:{[x] :x.hh}
f:{[x;y] :x+y}

Now I want to use function f in a query as follows:

select f each (columnOne,d[columnTwo]) from myTable

Hence, I first want to convert one column to the corresponding numbers using function d. Then, using both columnOne and the output of d[columnTwo], I want to calculate the outcome of f.

Clearly, the approach above does not work, as it fails with a 'rank error.

I've also tried select f ./: (columnOne,'d[columnTwo]) from myTable, which also doesn't work.

How do I do this? Note that I need to input columnOne and columnTwo into f such that the corresponding rows still match. E.g. input row 1 of columnOne and row 1 of columnTwo simultaneously into f.


Solution

  • I've also tried select f ./: (columnOne,'d[columnTwo]) from myTable, which also doesn't work.

    You're very close with that code. The issue is the d function, in particular the x.hh within function d - the .hh notation doesn't work in this context, and you will need to do `hh$x instead, so d becomes:

    d:{[x] :`hh$x}
    

    So making only this change to the above code, we get:

    q)d:{[x] :`hh$x}
    q)f:{[x;y] :x+y}
    q)myTable:([] columnOne:10?5; columnTwo:10?.z.t);
    q)update res:f ./: (columnOne,'d[columnTwo]) from myTable
        columnOne columnTwo    res
        --------------------------
        1         21:10:45.900 22
        0         20:23:25.800 20
        2         19:03:52.074 21
        4         00:29:38.945 4
        1         04:30:47.898 5
        2         04:07:38.923 6
        0         06:22:45.093 6
        1         19:06:46.591 20
        1         10:07:47.382 11
        2         00:45:40.134 2
    

    (I've changed select to update so you can see other columns in result table)

    Other syntax to achieve the same:

    q)update res:f'[columnOne;d columnTwo] from myTable
        columnOne columnTwo    res
        --------------------------
        1         21:10:45.900 22
        0         20:23:25.800 20
        2         19:03:52.074 21
        4         00:29:38.945 4
        1         04:30:47.898 5
        2         04:07:38.923 6
        0         06:22:45.093 6
        1         19:06:46.591 20
        1         10:07:47.382 11
        2         00:45:40.134 2
    

    Only other note worthy point - in the above example, function d is vectorised (works with vector arg), if this wasn't the case, you'd need to change d[columnTwo] to d each columnTwo (or d'[columnTwo])

    This would then result in one of the following queries:

    select res:f'[columnOne;d'[columnTwo]] from myTable
    select res:f ./: (columnOne,'d each columnTwo) from myTable
    select res:f ./: (columnOne,'d'[columnTwo]) from myTable