Search code examples
jsonkeyjqrename

how to test if array contains item, as is, not some subset of it


So it seems that I fell for contains function definition, since:

yq -n '["hyper"]|contains(["pe"])'

'surprisingly' returns true. I don't know what usecase this have, still new to funcitolan world but it's clearly shown in docs as:

jq 'contains(["baz", "bar"])'
Input   ["foobar", "foobaz", "blarp"]
Output  true

So how to trivially write exact matching, string-is-contained-in-array-contains?

yq -n '["hyper"] as $i | $i - ["pe"] != $i'

? Or what would be correct solution?


Solution

  • Please specify which implementation of yq you are using. As you are referring to examples for the contains filter in the manual to stedolan/jq, I assume you are using kislyuk/yq, which is a YAML-wrapper around jq.

    jq's contains tests if its argument is partially contained in the input. As this is done recursively, it also affects the string items of your array, not only the surrounding array itself. And as "pe" is contained in "hyper", it evaluates to true.

    jq offers the any filter to test if in a given stream at least one item evaluates to true for a given filter. For that filter you could use the equals == operator which evaluates to true for exact matches, and for the stream, if omitted, any will default to the items of an input array.

    $ yq -n '["hyper"] | any(. == "pe")'
    false
    
    $ yq -n '["hyper"] | any(. == "hyper")'
    true
    

    Just in case, if you do use the other implementation mikefarah/yq, it offers a similar function called any_c (as it is not based on jq and hence has a (sometimes) different syntax):

    $ yq -n '["hyper"] | any_c(. == "pe")'
    false
    
    $ yq -n '["hyper"] | any_c(. == "hyper")'
    true