egor7
egor7

Reputation: 4941

Indexing dictionary in depth, two cases

When indexing dictionary in depth I've found different results in the same (as I think) constructions:

q)d:`a`b!(1 2 3;4 5 6)
q)d[`a`b;0]
1 4
q)d[`a`b]0
1 2 3

Why is this happening? How q understands and distinguishes two different cases? Before this I was confident that, for example, calling dyadic function f[a;b] and f[a]b are the same. And now I am not sure even about this.

Upvotes: 0

Views: 355

Answers (3)

Jorge Sawyer
Jorge Sawyer

Reputation: 1341

What's happening here is that d[`a`b] has the depth/valence as d. So when you apply d[`a`b]0 the zero is not indexing at depth. You get expected results if you don't index multiple values of your dictionary:

q)d[`a`b;0]~d[`a`b][0]
0b
q)d[`a;0]~d[`a][0]
1b
q)d[`b;0]~d[`b][0]
1b

This is more clear if you instead consider a 2x3 matrix which has identical behavior to your original example

q)M:(1 2 3;4 5 6)
q)M[0 1;0]
1 4
q)M[0 1][0]
1 2 3

Indexing any one row results in a simple vector

q)type M[0]
7h
q)type M[1]
7h

But indexing more than one row results in a matrix:

q)type M[0 1]
0h

In fact, indexing both rows results in the same exact matrix

q)M~M[0 1]
1b

So we should expect

q)M[0]~M[0 1][0]
1b

as we see above.

None of this should have an impact on calling dyadic functions, since supplying one parameter explicitly results in a function projection and therefore the valence is always reduced.

q)type {2+x*y}
100h
q)type {2+x*y}[10]
104h

Upvotes: 1

terrylynch
terrylynch

Reputation: 13572

EDIT - Adam beat me to it!

I don't think you can consider a function invocation f[a;b] or f[a]b as equivalent to indexing. f[a]b for a function is a projection but you can't project indexing in the same way. A function has a fixed valence, aka fixed number of inputs, but indexing can be done at any depth.

If you take your dictionary and fabricate it to have more depth, you can see that you can keeping indexing deeper and deeper:

q)d:{`a`b!2#enlist value x}/[1;d]
q)d[`a`b;1;1]
5 5
q)d:{`a`b!2#enlist value x}/[2;d]
q)d[`a`b;1;1;1;1]
5 5
q)d:{`a`b!2#enlist value x}/[2;d]
q)d[`a`b;1;1;1;1;1;1]
5 5

Yet you can still index just at the top level d[`a`b]. So the interpreter has to decide if its indexing at the top level, aka d @ `a`b or indexing at depth d . (`a`b;0).

To avoid confusion it indexes at top level if you supply one level of indexing and indexes at depth if you supply more than one level of indexing. Thus no projections (at least not in the same manner).

And as mentioned above, functions don't have this ambiguity because they have a fixed number of parameters and so they can be projected.

Upvotes: 1

Adam Bonham
Adam Bonham

Reputation: 615

To index at depth you either need semi colons separating your arguments, or use the dot. Your second example,

d[`a`b] 0

Is taking the 2 lists from the dictionary values and then indexing to return the first. While

d[`a`b;0]

or

 d .(`a`b;0)

Is taking the 2 lists, and then indexing at depth, taking the first element of each, due to the semi colon/dot

When you call a dyadic function it is expecting two parameters, passing one inside the square brackets creates a projection, which is basically using an implicit semi colon, so

f[a]b

is the same as

f[a;]b

which is the same as

f[a;b]

The result of

f[a]

is a projection which is expecting another argument, so

f[a] b

evaluates f[a], then passes argument b to this function, with usual function application via juxtaposition

Your dictionary indexing example does not create a projection, and hence the indexing is not expecting any more arguments, so the first indexing

d[`a`b]

is evaluated immediately to give a result, and then the second index is applied to this result. It would work the same for a monadic function

q){5+til x}[5] 2
7

Like the top level dictionary index, the application is carried out and then the result is indexed, as only one argument was expected, with no projection involved

Upvotes: 1

Related Questions