Why is accessing an array by index different if the index is an expression instead of a literal?

121 Views Asked by At

What works fine

Suppose we have the following data:

[[1,2], [3,4]]

To extract just the number 3 we could use a double filter. The manual says:

If the predicate expression is an integer, or an expression that evaluates to an integer, then the item at that position (zero offset) in the input sequence is the only item selected for the result sequence. Source

or

JSON arrays are used when an ordered collection of values is required. Each value in the array is associated with an index (position) rather than a name, so in order to address individual values in an array, extra syntax is required to specify the index. This is done using square brackets after the field name of the array. If the square brackets contains a number, or an expression that evaluates to a number, then the number represents the index of the value to select. Indexes are zero offset, i.e. the first value in an array arr is arr[0]. If the number is not an integer, then it is rounded down to an integer. If the expression in square brackets is non-numeric, or is an expression that doesn't evaluate to a number, then it is treated as a predicate. Source

Those two could be seen as a contradiction, because in the first case it says "[it] is the only item selected in the result sequence" while the second speaks about a "value to select". However both sections are seem to indicate that a literal integer is the same as an expression that evaluates to an integer.

So this:

$[1][0]

Will get the expected result: 3.

Question

The manual says that the predicate can also be an expression that evaluates to an integer. I thought that for example 1+0 would be an expression that evaluates to an integer. So I tried this:

$[1+0][0]

To my surprise this changes the result to:

[3,4]

I can "fix" this by using $[1+0][0][0]. What is happening here?

What I tried

Could it be that 1+0 not an expression that evaluates to an integer? In this case the manual says that it would be evaluated like a predicate. In this case I guess it might return a sequence (with incidentally just a single value). But in this case: What is an expression that evaluates to an integer?

I get the same if using a variable...:

(
    $index := 1
    $[$index][0]
)
1

There are 1 best solutions below

0
On

Quick answer: you can try with ($[1-1])[0]

I went deep in the code, and it seems that it is related to the input that you provide, and on how "binary" vs "number" filters are handled.

In this specific context, when you write "1+0" in a complex object (in this case, an array of array), the inner array is added inside an object. When filtered, a new object is created and the inner array is pushed inside it. When you index the object with [0], you will retrieve the inner array.

On the opposite side, when you input $[1][0], the outer array is parsed instantly as an array, and so that's why it works.

Basically, "1+0" is a "binary" expression, as all the expression that you can write, while "0" is a "number" that is handled in another way.

You can check the code here: Github jsonata repo from the method evaluateGroupExpression and the methods below: