#jq
#jq #белый список
Вопрос:
Поскольку пример стоит тысячи слов, скажем, у меня есть следующий поток JSON:
{"a": 0, "b": 1}
{"a": 2, "b": 2}
{"a": 7, "b": null}
{"a": 3, "b": 7}
Как я могу сохранить все объекты, для которых .b
свойство является одним из [1, 7]
(на самом деле список намного длиннее, поэтому я не хочу этого делать select(.b == 1 or .b == 7)
). Я ищу что-то вроде этого: select(.b in [1, 7])
, но я не смог найти то, что я ищу на странице руководства.
Ответ №1:
Это $value in $collection
может быть достигнуто с помощью шаблона select($value == $collection[])
. Более эффективной альтернативой было бы select(any($value == $collection[]; .))
Поэтому ваш фильтр должен быть таким:
[1, 7] as $whitelist | select(any(.b == $whitelist[]; .))
Наличие массива в переменной имеет свои преимущества, поскольку позволяет легко изменять белый список с помощью аргументов.
$ jq --argjson whitelist '[2, 7]' 'select(any(.b == $whitelist[]; .))'
Комментарии:
1. Первоначальный вопрос относился к потоку, а не к массиву, и в этом случае вам не нужно было бы использовать
map
.2. Также обратите внимание, что
[1, 7][]
может быть выражено как(1, 7)
.3. Первоначально в вопросе указывалось, что входными данными был массив, но это было изменено после того, как я ответил.
4. Да, я не прав, отредактировав вопрос, как только я увидел ваш ответ, я просто хотел сделать вопрос более целенаправленным. @SantiagoLapresta где документация для
(1, 7)
конструкции, кажется, я не могу найти ее на странице руководства.5. @foo: Ключ в том, что с помощью запятых выражение выдает несколько значений. При использовании
[]
в массиве это выражение также выдает несколько значений. Я предполагаю, что соответствующий раздел в руководстве находится на [,
] .[1, 2, 3][]
эквивалентно1, 2, 3
.
Ответ №2:
Следующий подход с использованием index/1 аналогичен тому, который был первоначально запрошен («.b в [1, 7]»), и может быть заметно быстрее, чем использование .[] внутри select
, если белый список большой.
Если ваш jq поддерживает —argjson:
jq --argjson w '[1,7]' '. as $in | select($w | index($in.b))'
В противном случае:
jq --arg w '[1,7]' '. as $in | ($w|fromjson) as $w | select($w | index($in.b))'
или:
jq '. as $in | select([1, 7] | index($in.b))'
Обновить
30 января 2017 года была добавлена встроенная функция с именем IN
для эффективной проверки того, содержится ли объект JSON в потоке. Его также можно использовать для эффективной проверки членства в массиве. Например, приведенный выше вызов с помощью —argjson может быть упрощен до:
jq --argjson w '[1,7]' 'select( .b | IN($w[]) )'
Если ваш jq не имеет IN/1
, то до тех пор, пока ваш jq имеет first/1
, вы можете использовать это эквивалентное определение:
def IN(s): . as $in | first(if (s == $in) then true else empty end) // false;