aioobe
aioobe

Reputation: 421090

In jq, how to select objects where an array contains at least one value (intersection non-empty)

I have input like this:

{ "prop": ["apple", "banana"] }
{ "prop": ["kiwi", "banana"] }
{ "prop": ["cherry", "orange"] }

How do I print objects where prop contains at least one of kiwi and orange?

(The list of interesting values is longer than just 2, so I'd like to leverage the any function somehow.)

I've tried the following

jq 'select(any(.prop[] | contains(["kiwi", "orange"])))' < input.json

and various variants of the above, but can't figure out the right expressions.

Upvotes: 2

Views: 2966

Answers (3)

JakeRobb
JakeRobb

Reputation: 1970

The above answers worked for me in jq 1.7, but they failed in jq 1.6 (which is what's preinstalled on a GitHub Actions ubuntu-latest runner in February 2024, and I don't want the performance hit of installing something better during every CI run).

Here's what I came up with that works correctly and consistently in both 1.6 and 1.7:

def intersects(a; b):
  any(a[] as $aElem | b | index($aElem));

Use as follows:

intersects(["a", "b", "c"]; ["c", "d", "e"]) # true

or

intersects(["a", "b", "c"]; ["d", "e", "f"]) # false

Upvotes: 0

peak
peak

Reputation: 116870

The stream-oriented version of the built-in function any can be most easily used if one bears in mind its signature:

def any(generator; condition):

So we are led to:

select( any( .prop[]; . == "kiwi" or . == "orange" ))

or more succinctly:

select( any(.prop[]; IN("kiwi", "orange")))

whitelist

If the values of interest are provided as a JSON array, say $whitelist, you could tweak the above by substituting $whitelist[] for the explicit stream of values:

select( any(.prop[]; IN($whitelist[]) ))

Upvotes: 4

oguz ismail
oguz ismail

Reputation: 50785

I think you're looking for IN/2. It's implemented using any, but is far easier to grasp.

select(IN(.prop[]; "kiwi", "orange"))

Online demo

Upvotes: 2

Related Questions