jq를 사용하여 json 배열 요소의 위치를 ​​조건부로 변경하는 방법은 무엇입니까?

jq를 사용하여 json 배열 요소의 위치를 ​​조건부로 변경하는 방법은 무엇입니까?

조건에 따라 배열 요소의 위치를 ​​변경하고 싶습니다(배열 요소의 인덱스 변경). 이것을 jq로 번역하는 방법을 모르겠습니다. 이것은 다음과 같습니다.기능의언어.
기본적으로 배열을 정렬하고 싶지만비교적특정 요소의 위치는 변경되지 않은 상태로 유지되어야 합니다.

for each element:
if element.role==master => record type
  for each element:
    if element.type == recorded type
      reposition the element to be below its master of similar type 

예를 들어 더 잘 설명할 수 있습니다. 고려하다 input.json. "x" 유형의 모든 비주요 요소를 주 요소 아래로 이동하는 방법아니요변화비교적동일한 유형의 비마스터 상태입니다. ("num" 인수는 무시합니다. 상대성을 표시하는 데에만 사용됩니다.)

입력.json

[
    {
        "type": "A",
        "role": "master"
    },
    {
        "num": 1,
        "type": "A"
    },
    {
        "type": "C",
        "role": "master"
    },
    {
        "num": 4,
        "type": "B"
    },
    {
        "num": 2,
        "type": "B"
    },
    {
        "type": "B",
        "role": "master"
    },
    {
        "num": 3,
        "type": "B"
    },
    {
        "num": 4,
        "type": "A"
    },
    {
        "num": 2,
        "type": "A"
    },
    {
        "num": 0,
        "type": "C"
    },
    {
        "num": 5,
        "type": "C"
    },
    {
        "num": 1,
        "type": "A"
    },
    {
        "num": 1,
        "type": "B"
    }
]

타겟.json

[
    {
        "type": "A",
        "role": "master"
    },
    {
        "num": 1,
        "type": "A"
    },
    {
        "num": 4,
        "type": "A"
    },
    {
        "num": 2,
        "type": "A"
    },
    {
        "num": 1,
        "type": "A"
    },
    {
        "type": "C",
        "role": "master"
    },
    {
        "num": 0,
        "type": "C"
    },
    {
        "num": 5,
        "type": "C"
    },
    {
        "type": "B",
        "role": "master"
    },
    {
        "num": 4,
        "type": "B"
    },
    {
        "num": 2,
        "type": "B"
    },
    {
        "num": 3,
        "type": "B"
    },
    {
        "num": 1,
        "type": "B"
    }
]

보시다시피:
1- 마스터의 상대 위치는 동일하게 유지됩니다(A - C - B).
2- 동일한 유형의 비마스터의 상대 위치는 동일하게 유지됩니다.

(이 문제는 알고리즘 문헌에 이름이 있는 것 같아요? 내부 정렬?)

답변1

방법:

  1. 마스터 목록을 가져오고 해당 유형을 추출합니다. 이 순서 세트는 나머지 데이터를 어떤 순서로 처리할지 알려줍니다.

    ( .[] | select(.role == "master").type )
    

    주어진 데이터에 대해 이는 집합 "A", "C", 입니다 "B".

  2. 이 컬렉션을 반복하여 마스터 역할이 있는 해당 유형의 요소를 추출한 다음 해당 유형은 있지만 마스터 역할이 없는 요소를 추출합니다.

    루프는 $type루프 변수로 수행됩니다.

    ( .[] | select(.role == "master").type ) as $type
    

    마스터를 추출한 다음 비마스터를 추출합니다.

    ( .[] | select(.type == $type and .role == "master" ) ), 
    ( .[] | select(.type == $type and .role != "master" ) )
    
  3. 모든 것을 배열에 넣으십시오. 여기에는 모든 것을 배치 [하고 ]둘러싸는 작업이 포함됩니다.

우리는 마침내 얻습니다

[
    ( .[] | select(.role == "master").type ) as $type |
    ( .[] | select(.type == $type and .role == "master" ) ), 
    ( .[] | select(.type == $type and .role != "master" ) )
]

실제로 여기서는 정렬이 진행되지 않습니다. 우리는 순서대로 데이터를 추출하고 그로부터 새로운 배열을 만듭니다.


대안: 먼저 해당 유형뿐만 아니라 배열에서 전체 주요 요소를 추출합니다.

[
    ( .[] | select(.role == "master") ) as $master |
    $master,
    ( .[] | select(.type == $master.type and .role != "master" ) )
]

또 다른 접근 방식: 먼저 초기 배열의 그룹화를 사용하여 기본 요소를 다른 요소와 분리합니다. 이는 역할이 있는 요소만 있거나 master역할이 전혀 없다고 가정합니다.

group_by(.role) |
[
    .[1][] as $master |
    $master,
    ( .[0][] | select(.type == $master.type )
]

여기서 첫 번째 줄은 원래 배열을 .[0]역할이 없는 요소와 .[1]역할이 있는 요소를 포함하는 두 부분으로 분할하는 것으로 시작됩니다.

그런 다음 in의 주요 요소를 반복하여 현재 유형에 해당하는 요소를 선택합니다 .[1]..[0]$master

각 기본 요소 뒤에 기본이 아닌 요소가 오는 배열을 만듭니다.

관련 정보