jq: групповые и вложенные массивы json - PullRequest
0 голосов
/ 17 мая 2019

Допустим, у меня есть: [[1,2], [3,9], [4,2], [], []]

Я хотел бы знать скрипты для получения:

  • Количество вложенных списков, которые не являются или не являются-empty.т.е. хотите получить: [3,2]

  • Количество вложенных списков, которые содержат или не содержат число 3. т.е. хотите получить: [1,4]

  • Количество вложенных списков, для которых сумма элементов равна / не меньше 4.т.е. хочу получить: [3,2]

т.е. основные примеры вложенных разделов данных.

1 Ответ

1 голос
/ 17 мая 2019

Поскольку stackoverflow.com не является сервисом кодирования, я ограничу этот ответ первым вопросом, надеясь, что он убедит вас в том, что изучение jq стоит усилий.

Давайте начнем с уточнения вопроса о количестве списков «которые являются / не пусты», чтобы подчеркнуть, что первое число в ответе должно соответствовать количеству пустых списков (2), а второе число - остальным (3). То есть, обязательный ответ должен быть [2,3].

Решение с использованием встроенных фильтров

Следующим шагом может быть вопрос, можно ли использовать group_by. Если порядок не имеет значения, мы можем просто написать:

group_by(length==0) | map(length)

Это возвращает [3,2], что не совсем то, что мы хотим. Теперь стоит проверить документацию о том, что group_by должен делать. При проверке деталей на https://stedolan.github.io/jq/manual/#Builtinoperatorsandfunctions, мы видим, что по проекту group_by действительно сортирует по значению группировки.

Поскольку в jq, false < true, мы могли бы исправить нашу первую попытку, написав:

group_by(length > 0) | map(length)

Это хорошо, но поскольку group_by делает так много работы, когда все, что нам действительно нужно - это способ подсчета, ясно, что мы должны быть в состоянии найти более эффективное (и, надеюсь, менее непрозрачное) решение.

Эффективное решение

По своей сути проблема сводится к подсчету, поэтому давайте определим общий фильтр tabulate для получения количества различных строковых значений. Вот определение, которое будет достаточно для настоящих целей:

# Produce a JSON object recording the counts of distinct
# values in the given stream, which is assumed to consist 
# solely of strings.
def tabulate(stream):
  reduce stream as $s ({}; .[$s] += 1);

Эффективное решение теперь можно записать всего в две строки:

tabulate(.[] | length==0 | tostring )
| [.["true", "false"]]

QED

приписка

Функция с именем tabulate выше иногда называется bow (для «мешка слов»). В некотором смысле это было бы лучшим именем, тем более что было бы целесообразно зарезервировать имя tabulate для аналогичной функциональности, которая будет работать для произвольных потоков.

...