kdb q - lookup in nested list - kdb

Is there a neat way of looking up the key of a dictionary by an atom value if that atom is inside a value list ?
Assumption: The value lists of the dictionary have each unique elements
Example:
d:`tech`fin!(`aapl`msft;`gs`jpm) / would like to get key `fin by looking up `jpm
d?`gs`jpm / returns `fin as expected
d?`jpm / this doesn't work unfortunately
$[`jpm in d`fin;`fin;`tech] / this is the only way I can come up with
The last option does not scale well with the number of keys
Thanks!

You can take advantage of how where operates with dictionaries, and use in :
where `jpm in/:d
,`fin
Note this will return a list, so you might need to do first on the output if you want to replicate what you have above.

Why are you making this difficult on yourself? Use a table!
q)t:([] c:`tech`tech`fin`fin; sym:`aapl`msfw`gs`jpm)
q)first exec c from t where sym=`jpm
You can of course do what you're asking:
first where `jpm in'd
but this doesn't extend well to vectors while the table-approach does!
q)exec c from t where sym in `jpm`gs

I think you can take advantage of the value & key keywords to find what you're after:
q)key[d]where any value[d]in `jpm
,`fin
Hope that helps!
Jemma

The answers you have received so far are excellent. Here's my contribution building on Ryan's answer:
{[val;dict]raze {where y in/:x}[dict]'[val]}[`msft`jpm`gs;d]
The main difference is that you can pass a list of values to be evaluated and the result will be a list of keys.
[`msft`jpm`gs;d]
Output:
`tech`fin`fin

Related

How do I find the index of a json object in an array based off of a value of its properties

I am fairly new to Redis and RedisJson and I have been through all the documentation I can get my hands on, but I still can't seem to figure this one out. I am hoping someone could shed some light on this situation to help me understand. My end goal is to be able to remove the JSON object from the responses array using JSON.ARRPOP. I need to get the index of the object first and I can't seem to do that.
Here is my object structure:
JSON.SET test:1 $ '{ "responses":[{"responseId":"29aab59c-10b0-48c0-ab91-8873fb6e2238"},{"responseId":"ab79f09b-8e31-41f4-9191-ef89a34964d3"}]}'
Check the path:
JSON.GET test:1 $.responses[*].responseId
RETURNS:
"["29aab59c-10b0-48c0-ab91-8873fb6e2238","ab79f09b-8e31-41f4-9191-ef89a34964d3"]"
Ok looks good I have an array of two strings lets get that index of 29aab59c-10b0-48c0-ab91-8873fb6e2238.
JSON.ARRINDEX test:1 $.responses[*].responseId '"29aab59c-10b0-48c0-ab91-8873fb6e2238"'
RETURNS:
(nil)
(nil)
It appears to have searched but found nothing?
At first I thought it was an escape character issue but I get the same results with responeIds as integers 1 and 2.
Any help here would be greatly appreciated. Thanks!
JSON.ARRINDEX can only search for scalar values. Objects and arrays are not scalars so you can't search for them.
For your use case you should look at https://redis.io/docs/stack/search/indexing_json/

How to create a list of length x with identical elements?

I would like to create a list in q/kdb of variable length x which contains the same element e repeated. For example:
x:4;
e:`this;
expected_result:`this`this`this`this
As mentioned by all, # is the best solution in the singular case. If you wanted to duplicate multiple items into a larger single list, then where can achieve this nicely
q)`this`that where 4 2
`this`this`this`this`that`that
Take is what you're looking for:
https://code.kx.com/v2/ref/take/
q)x:4
q)e:`this
q)x#e
`this`this`this`this
You can do this using # https://code.kx.com/v2/ref/take/
q)n:4
q)vals:`this
q)n#vals
`this`this`this`this
Use '#'(take) function:
q) x:4
q) e:`this
q) x#e

How to convert "like each" into a functional form?

Let's say I have a column of a table whose data type is a character array. I want to pass in a functional select where clause, where the column is in a list of given strings. However, I cannot simply use (in; `col; myList) for reasons. Instead, I need to do the equivalent of:
max col like/: myList
which effectively gives the same result. However, I have tried to put this in functional form
(max; (like/:; `col; myList))
And I am getting a type error. Any ideas on how I could make this work?
A nice trick when dealing with this problem is using parse on a string of the select statement you want to functionalize. For example:
q)parse"select from t where max col like/: myList"
?
`t
,,(max;((/:;like);`col;`myList))
0b
()
Or specifically in your case you want the 3rd element of the result list (the where clause):
q)(parse"select from t where max col like/: myList")2
max ((/:;like);`col;`myList)
I even think using this pattern in your actual code can be a good idea, as functionalized statements like max ((/:;like);`col;`myList) can get pretty unreadable pretty quickly!
Hope that helps!
(any; ((/:;like); `col; enlist,myList))
it should be: (max;((/:;like);`col;`mylist))

How should list be represented in ASP (Answer Set Programming)?

A processor 'a' takes care the header 'a' of a message 'a_b_c_d' and passes the payload 'b_c_d' to the another processor in the next level as following:
msg(a, b_c_d).
pro(a;b;c;d).
msg(b, c_d) :- pro(X), msg(X, b_c_d).
msg(c, d) :- pro(X), msg(X, c_d).
msg(d) :- pro(X), msg(X, d).
#hide. #show msg/2. #show msg/1.
How should I represent list 'a_b_c_d' in ASP, and change the above to general cases?
No, official way, but I think most people don't realize you can construct cons-cells in ASP.
For instance, here's how you can get items for all lists of length 5 from elements 1..6
element(1..6).
listLen(empty, 0).
listLen(cons(E, L), K + 1) :- element(E); listLen(L, K); K < 5.
is5List(L) :- listLen(L, 5).
#show is5List/1.
resulting in
is5List(cons(1,cons(1,cons(1,cons(1,cons(1,empty))))))
is5List(cons(1,cons(1,cons(1,cons(1,cons(2,empty))))))
is5List(cons(1,cons(1,cons(1,cons(1,cons(3,empty))))))
...
There is no 'official' way to handle lists in ASP as far as I know. But, DLV has built-in list handling similar to Prolog's.
The way you implement a list, the list itself cannot be used as a term and thus what if you want to bind between variables in the list and other elements of a rule? Perhaps you would like something such as p(t, [q(X), q(Y)]) :- X != Y.
You can try implementing a list as (a, b, c) and an append predicate but the problem is ASP requires grounding before computing answer-sets. Consequently a list defined in this way whilst more like lists in Prolog would mean the ground-program contains all ground-instances of all possible lists (explosion) regardless of whether they are used or not.
I therefore come back to my first point, try using DLV instead of Clingo if possible (for this task, at least).
By using index, I do have a way to walk a list, however, I do not know this is the official way to handle a list in ASP. Could someone has more experience in ASP give us a hand? Thanks.
index(3,a). index(2,b). index(1,c). index(0,d).
pro(a;b;c;d). msg(3,a).
msg(I-1,N) :- pro(P), msg(I,P), index(I,P), I>0, index(I-1,N).
#hide. #show msg/2.
You can use s(ASP) or s(CASP) ASP systems. Both of them support list operations like prolog. You might need to define the list built-in in ASP .

Exclude non-matching atoms from list

I would like to collect a list of atoms and pass a list to an object or abstraction that will pass through the matching atoms without modifying the order of the list, or removing duplicates.
(hello how are you)
|
[desiredobject how are you]
|
[print]
Ideally this would print (how are you). If I were to put in (how how how) I would get back the same message. But if I were to put in (jfj jfj jfj) I would get nothing.
[zl] is useful but I am looking for the inverse behaviour of [zl filter].
EDIT:
I came up with the following solution that works equally well to the solution #mattijs posted. My solution uses [uzi] to give indices of the symbols in a list. The indices output of [zl filter] is fed to [zl unique] in order to strip out undesired indices. This new list is fed to [zl lookup] in order to convert back to the symbols. The (fake) message is inserted in case [zl filter] filters everything and then [zl unique] would have no output.
----------begin_max5_patcher----------
1385.3oc0Z0scipBE95jmBVdclYo3Owbt67bz0r5hnzDZMfGEa6zYMu6GDvD
v+hoMM0dQzHHvlu89aCrc+mkKb1xdEW5.9GvcfEK9yxEKjEUWvB8yKbNfdMI
CUJeMGJ9E11GcVophiekKKNGjTvJKKvOfKvzDbyKPqNvp3YXtr0Pcoph3+NG
qFZGmUhefeoq9AFkWRdSVoG7mtm5KBscWki3I6Izc2WfS3pdKHVzDP755qdt
t02fhqG6dRpTjESie3CcLFSJ5fbLc92BBJywbDvEZLQCJhFPxvOiKJILpTNW
oKGkmaT7BilTijOxjcTzpiEQnph7NVTA9YRS6cOVJpPLO4hIYUgRHeMNxQU4
eW1L3m.gvvn5IdPP800wxaQvfSvfPQuKik7DN0bbbX4XJglWfKwTNh2RLbRw
Ofpx322uJxt9GPI3AabuX8BmcEjTFsVHrZYcwMC2c.uPopMzbxHeCJJumFWJ
lGUkaQE0v51Lrg4ivBlwxrq5nlTPDPTxADGyIJgE5drSIGxKHTt0.goHQeru
TPExxr5JUMO2SMoBkcB9ERJeuruLgRwqSxaTANGwnTxNbI2tLNZWocIVLaSq
PSFtU4sX5RtVS20kK6YTSW97QEijAYXMYvS87kby.o1zUewpgVLdWydrKqGF
IswCkWggMWs5OCler4LKgc3.lpgzlh+6xkM+Y06DBa5Wig5nGyBbNKuJSXcA
pnj+qBCdgv2Cd.8DFH34G.DJHAUhABGMbbAXOpDPY.ATmWY0iYDJNgUoDe+A
0Wlv2.rWYUE61ZaH1QQ3MthvGpb45uQwRkJjf0CqJhbZIZs7MbEUHWOa5Kwz
bS3kXY5cKrLsVF21v7sLPlvC5ffDbTPZUafZDas9VPeHLzaizbxeiu5V6U06
rx9synRABNSh4cIDI8TN.FOMCG3svv4yZxp3HSdtF9ESR3fLv1O.GYKht68w
SNmQSjlZH29mO7mgiySh7tcDkC3xRzNbu.Z85dWEGyWI+Mv0wFqh4K853EOB
N5d6vwwcdq1Mwby+she66IMKCOq66P+4BbtqfUkOOQSswYn+YQS3r.M+Av6c
Rwkmz5yCGcgSyYY37fjW8FYXbzeLbTtrypS2+bwU8ZQAQmy9LXybgsOC24qF
KUGV97a7MX8rAKYrmlqtN8UNMCiOKbFLWfyl3.vdAfJvfeyplcmQSu2S8I+8
BNK39NVW5TH+pC7w.Q3RJb002OpWxpJRZfCczf.1RYJtjSnGC.5cmDXfm0Kt
mjlZGvQUL5Jqi3mJ1pSxD4RE4dDk9k45sRMSj45CaLcb1cVHy9STjmOR7jA4
fIZXbfjlyDaUPS17bCp2njm2Z02VPQ1MdvW8EX7B7qeO4S1hy7ABV+sSq0CG
5KyETvDk4vuehr+7QjWOUi4Me+j4P3GyGTnbWwwJ+MlO.g5sMGKOTWmXIdCv
fZ0AbJXf6rQu0inLhdalHyvoJyyGNcn+krF87PlibuDbdFsgyorI4nqEGD7q
klojgSI5Yb58hgPbJo6QbdAYaEWcrEyrI4il2DmOuLtfjInWgXjAenAcWFaK
JSm+LGaaO4rvxSfn7pR0OkzQx9SJb57xcOkb+gabjulvGMMj7TAWPsbz5n1e
.AqubW7HogzUDUd7gGA5eeUnBLxSFSPIpD3OJpr91fJ01J5eeY1J5HkprXFG
UbutnxPIzmL6l5ENbuf4r24RSOOn9Hiikld2H5wdbVFCLCbcnYGJ.xMbTygo
AMxlZGwLER0dEUMd0YkTnUHxF5PSV6lu6JncW8rilaxxy5oJOt2D4o0P0u7D
eyDG37Bcftelxix3tUh2VKJsR31VIaa2DscnjrULN+c4+C3uv.MC
-----------end_max5_patcher-----------
So basically you want to compare each item in list 1 to each item in list 2 and only pass through an item in list 1 if it is also in list 2?
It's possible this can be simplified btw, just a quick solution:
----------begin_max5_patcher----------
1198.3oc4Z1saihCEG+ZxSAhq6NBayWYuXk1mipQUFvIwcH1HvosyLpu6KXC
IlDRpIkkwilKBowewe94y4Xr64mqb7R4uQp8b+a2Gccb94JGGYQsE3z8aGu8
32xJv0xl4wHuxSe16AUUBxaBYwktYU755JxFREgkQ5avFNSTS+AosQ.3W76J
lcXOkUPDxwDdpP9AQeoftRKwhrcT11mpHYBkRQnlAxMtc3bA99seAat590tt
nFEw2KIp164crJZtTtMOB+EBpKRFdur0d+aEEW3oeyIUc7nCHMcfVPdgTUS4
LMo53gKK0J1QqKsT7YtbfBe3XQTlpHvwhpHuP66+ZUguupe3OQ.4yr7RTf7q
fDM.zLGtsfm8Mh7g0uuvbxFyGAdIgMVq6uLrkTVYEolvDXQm30uq3CEhmF2R
XX8avYjq14Qmgb71VQy4rVQLnmsE2e6dzEDJsUB00srELb4HcVv4Eo3p1ohz
Bxfo3FuCLitGKHBpROP+i8iturhxDCFKBC2LF6pa7OJJFLTpZdYjZxarBxHu
RyE6ji0IZMveU29R2ucP42x+cnOrvM0sPulqLkcgCLXXEZNwPsZFwQNzWyEF
A+R3PG4wclSwrsdOn4TetiML57GhyLc5q78Uq5+iGlebREMANlUZBtMMiWKo
IREPL97vhePnwKnXnUPw+w0+dfH7dgH.FnLFWOEaRoS+0.YfU.xsMgrVTRFo
.YnzPDE7YMGQVAEEtEKbLRkWMLNZJ1i2L9HHwJP4OJbYMquMqljFwRDLQ90Z
CMIuIKisEVtshenbQoYHPhwDokYHZNnYjsPyJx1eAVlvP4dZB7mCVFZIALS+
0DvbZKf+guTIHvVLMqOjtnllqUd1qk7L.NGlln+nMMApXkymoIb4v4dRcMdK
YTdti+pKth39c9gE8EM6np5K06IARt6WzD.9Sd2iPezrr6wELZo7Y26Z7v+d
4g5rI5VJNr+58t6k05BLiueOQcLQd+FPB.JZFQAxeIPgROdS2Kw2j24MHJ5F
rP+gELkG1SmMYAkcsi4SJp15GmB07CUY8SB8qN3NTf4jZAkc7nZe7TfuyZ3N
Zd9viFUcr04kbJSzIP2uZz71T0cfoxNvpjMvXcGZW5t0LAXptA1EuMR2H6R2
ISQ2VjcBxT66X6i2FqaKi2lXm.sq3fPSiCBsL663ona6w9FZreYjcw6PS0ch
cYeartg1ktiLMdhk89I.C4cf8g6eCcKa2vpYgAsKc2t6Ry2siE85IlZmflyc
o0UXeFF4Uiegj+TysoY+tOgEhJZ5AgZin5o+z1BdJtnK2nNdvNGyHmQyjm+u
R+mOJ8ht1YOonf7pZ9yjjea3oedqS9bRI9ldtSocVCPUlb.Rfik3Ulmtbf.U
9xgF+7QMLc4fI2Hc4lQV97lmc69LmrLAoR0nOIKgAp+O7xQSw06gkwKCKasK
69LirDr1eVXIHL3DKStaV5Our7ZI3pLw9l.DAihC+OJqVA.z34Ki9y7B4Jti
TTvc+jA2lXV81QA+v60bvLzH65viYUQpyW3tiWW9BR5KCes0pG1nKVmd70nu
XxyXI4agZJ1B0ThoZBrXZBYh8Txm.SM+38U+GN+kvWC
-----------end_max5_patcher-----------
Hope that helps,
Mattijs