Помечать элементы на основе класса, к которому они принадлежат - PullRequest
0 голосов
/ 10 марта 2019

У меня есть поток элементов object_count.json, похожий на:

{
    "name":"apple",
    "count":10
}
{
    "name":"potato",
    "count":18
}
{
    "name":"stone",
    "count:7
}

Отдельно от потока, у меня есть два файла, каждый из которых перечисляет имена объектов своего класса:

cat fruits.txt
  apple
  peach

cat vegetables.txt
  potato
  tomato

Как создать поток, в котором каждому объекту из object_count.json присваивается имя соответствующего класса? I.e.:

{
    "name":"apple",
    "count":10
    "class":"fruit"
}
{
    "name":"potato",
    "count":18
    "class":"vegetable"
}
{
    "name":"stone",
    "count":7
    "class":"other"
}

Мы можем предположить, что в названии объекта есть только одна запись в object_count.json.


Я бы предпочел решение, которое:

  • хорошо работает 3, 4 и более классов - каждый по-прежнему указан в отдельном файле; все в порядке, если каждый класс жестко закодирован
  • object_count.json считается входным потоком, тогда как {fruits|vegetables}.txt предоставляется каждый как отдельный --rawfile аргумент

Версия, сообщенная JQ:

 $ jq --version
 jq-1.6

Мне удалось передать файл класса в качестве аргумента командной строки, но мне не удалось найти правильное выражение join / in, которое сработает и решит проблему:

cat object_count.json | jq -n --rawfile fruits "fruits.txt" '($fruits | split("\n") | map(select(. != "")) | sort) as $frts | inputs'

Ответы [ 2 ]

1 голос
/ 10 марта 2019

В соответствии с обновленным вопросом, вот решение, которое позволяет избежать потери содержимого object_count.json.

dictionary.jq

def trim: sub("^ +"; "") | sub(" +$"; "");

def dictionary(s):
  reduce (s | trim | select(length>0)) as $in ({};
     (input_filename | sub(".txt";"") | sub("s$";"")) as $class
     | .[$in] = $class );

dictionary(inputs) 

Вызов

jq --argfile class <(jq -n -R -f dictionary.jq *.txt)  '
 .class = ($class[.name] // "other")'  object_count.json

Postscript

Использование «other» в качестве имени класса по умолчанию может быть требованием, но если нет, то в подобных ситуациях, вероятно, было бы предпочтительнее использовать поток и использовать JSON null в качествезначение по умолчанию для ключа объекта.

0 голосов
/ 10 марта 2019

[Это ответ на оригинальный вопрос. Он допускает произвольное количество «классовых» файлов и требует только одного вызова jq. Решение, которое не включает в себя «усложнение» потока JSON, см. В другом месте на этой странице.]

Сложная задача - управлять неизвестным количеством TXT-файлов. Здесь мы предположим, что мы можем написать '* .txt', чтобы захватить их, поэтому вызов jq будет выглядеть так:

jq -n -R -f program.jq --slurpfile input object_count.json *.txt

Для построения словаря мы будем использовать следующие вспомогательные функции:

def trim: sub("^ +"; "") | sub(" +$"; "");

# construct the dictionary
def dictionary(s):
  reduce (s | trim | select(length>0)) as $in ({};
     (input_filename | sub(".txt";"") | sub("s$";"")) as $class
     | .[$in] = $class );

Теперь задача сводится к следующим трем строкам:

dictionary(inputs) as $class
| $input[]
| .class = ($class[.name] // "other")
...