키별로 값을 배열로 수집하는 방법은 무엇입니까?

키별로 값을 배열로 수집하는 방법은 무엇입니까?

중복된 키를 사용하여 주어진 입력 형식으로 입력합니다.

[
  {"key": "a", "value": 0},
  {"key": "a", "value": 1},
  {"key": "a", "value": 2},
  {"key": "b", "value": 3},
  {"key": "b", "value": 4},
  {"key": "b", "value": 5}
]

나는 생산하고 싶다

{"a": [0, 1, 2], "b": [3, 4, 5]}

즉, 각 고유 키에 대해 동일한 키를 가진 모든 값이 배열에 수집됩니다.

어떻게 해야 합니까 jq?

답변1

reduce()값으로 제공된 키에 지정된 값을 추가하여 결과 개체를 점진적으로 빌드하려면 in을 사용합니다 jq.valuekey

$ jq -c 'reduce .[] as $a ({}; .[$a.key] += [$a.value])' file
{"a":[0,1,2],"b":[3,4,5]}

이는 reduce()루프처럼 동작합니다. 이 경우에는 .[]최상위 배열의 모든 객체를 반복합니다. 각 객체에 대해 키 아래의 결과 객체(처음에는 빈 객체) $a에 값이 추가됩니다 .$a.value{}$a.key


사용을 좋아하는 분들을 위한 추가 팁 jq: 을 사용하면 debug표현식이 실행되는 동안 표현식의 어느 지점에서나 데이터를 볼 수 있습니다. 여기서는 루프의 각 반복 후 누산기 개체의 상태를 살펴봅니다 reduce().

$ jq -c 'reduce .[] as $a ({}; .[$a.key] += [$a.value] | debug)' file
["DEBUG:",{"a":[0]}]
["DEBUG:",{"a":[0,1]}]
["DEBUG:",{"a":[0,1,2]}]
["DEBUG:",{"a":[0,1,2],"b":[3]}]
["DEBUG:",{"a":[0,1,2],"b":[3,4]}]
["DEBUG:",{"a":[0,1,2],"b":[3,4,5]}]
{"a":[0,1,2],"b":[3,4,5]}

$a여기서는 각 반복에 할당된 값을 살펴보겠습니다.

$ jq -c 'reduce (.[]|debug) as $a ({}; .[$a.key] += [$a.value])' file
["DEBUG:",{"key":"a","value":0}]
["DEBUG:",{"key":"a","value":1}]
["DEBUG:",{"key":"a","value":2}]
["DEBUG:",{"key":"b","value":3}]
["DEBUG:",{"key":"b","value":4}]
["DEBUG:",{"key":"b","value":5}]
{"a":[0,1,2],"b":[3,4,5]}

답변2

group_by, map을 사용할 수 있습니다 .from_entries

jq 'group_by(.key) | map({key: .[0].key, value: [.[].value]}) | from_entries' data.json 

답변3

프로그래밍 언어를 이미 알고 있다면 매우 구체적인 언어를 사용할 필요 없이 쉽게 선택할 수 있습니다 jq. 그리고 perl:

$ perl -MJSON -l -0777 -ne '
    for (@{decode_json$_}) {push @{$out->{$_->{key}}}, $_->{value}}
    print encode_json $out' your-file.json
{"a":[0,1,2],"b":[3,4,5]}

답변4

사용행복하다(이전 Perl_6)

JSON 파서를 사용해야 합니다.

~$ raku -MJSON::Tiny -e 'my @json = from-json($_).list given slurp;  \
         my %accum.push: .<key> => .<value>.map(*.Num).Slip for @json>>.split(", ");  \
         .say for to-json(%accum.sort);'  file

입력 예:

[
  {"key": "a", "value": 0},
  {"key": "a", "value": 1},
  {"key": "a", "value": 2},
  {"key": "b", "value": 3},
  {"key": "b", "value": 4},
  {"key": "b", "value": 5}
]

출력 예(값이 Num-ified 및 Slipped, 즉 평면화됨):

[ { "a" : [ 0, 1, 2 ] }, { "b" : [ 3, 4, 5 ] } ]

마지막 코드는 to-json()끝에 호출을 추가합니다. 아마도 중간 단계에서 무슨 일이 일어나고 있는지 파악하는 가장 쉬운 방법은 각 개별 데이터 구조의 출력을 보여주는 것입니다. @json배열을 인쇄하면 .say for @json;다음이 반환됩니다.

{key => a, value => 0}
{key => a, value => 1}
{key => a, value => 2}
{key => b, value => 3}
{key => b, value => 4}
{key => b, value => 5}

%accum다음을 호출하여 생성된 해시를 사용 .<key> => .<value>(즉, 사용하지 않음)하면 .map(*.Num).Slip다음을 반환할 수 있습니다 .say for %accum.sort;.

[ { "a" : [ [ "0" ], [ "1" ], [ "2" ] ] }, { "b" : [ [ "3" ], [ "4" ], [ "5" ] ] } ]

Num상단에 게시된 것과 같은 코드를 호출하면 Int, "Flatten" 등의 함수 호출을 사용하여 값에 대해 다양한 작업을 수행할 수 있다는 점 참고하세요 .Slip

Raku의 JSON::Tiny모듈은 기본적으로 값을 문자열화합니다. 이러한 문자열화된 값을 (하위 목록이 아닌) 단일 목록으로 원하는 경우 Slip함께 묶습니다.

아래에서는 문자열화된 값이 Slip결합됩니다.

~$ raku -MJSON::Tiny -e 'my @json = from-json($_).list given slurp;  \
         my %accum.push: .<key> => .<value>.Slip for @json>>.split(", ");  \  
        .say for to-json(%accum.sort);'  file
[ { "a" : [ "0", "1", "2" ] }, { "b" : [ "3", "4", "5" ] } ]

따라서 여기에는 데이터 출력을 위한 많은 옵션이 있습니다. 가장 간단한 것은 상단에 있는 코드를 가져와서 마지막 to-json()호출을 제거하여 Raku의 %accum해시 "쌍" 표현을 확인하는 것입니다.

a => [0 1 2]
b => [3 4 5]

https://raku.land/cpan:MORITZ/JSON::Tiny
https://raku.org

관련 정보