Bash에서 연관 배열을 정렬하는 방법을 알고 싶습니다. 매뉴얼을 시도해 보았지만 정렬과 관련이 없는 것 같습니다.
현재 해결책은 모든 것을 에코하고 외부 프로그램을 사용하는 것입니다.key value | sort -k2
이것은 나에게 매우 비효율적으로 보입니다.
배열의 예는 다음과 같습니다.
A['192.168.2.2']=5
A['192.168.3.2']=1
A['192.168.1.1']=9
가장 일반적인 IP 주소 2개인 192.168.1.1과 192.168.2.2를 찾으겠습니다. 즉, 해당 값을 기준으로 배열을 정렬해야 합니다.
답변1
Zsh에는 목록을 정렬하는 방법이 내장되어 있습니다. 하지만 키와의 관련성을 유지하면서 값을 정렬하는 방법은 없는 것 같습니다.매개변수 확장 플래그그리고아래 첨자 기호, 이는 명시적인 루프가 필요함을 의미합니다. 값에 null 문자가 포함되어 있지 않다고 가정하면 null 문자와 연결된 값과 키의 배열을 만든 다음 정렬할 수 있습니다.
keys=("${(@k)A}")
values=("${(@v)A}")
combined=()
for ((i=1; i <= $#values; i++)) { combined[i]=($values[i]$'\0'$keys[i]); }
keys_sorted_by_decreasing_value=("${${(@On)combined}#*$'\0'}")
keys_of_the_top_two_values=("${(@)keys_sorted_by_decreasing_value[1,2]}")
@sch 편집: 처음 4줄은 다음과 같이 단순화할 수 있습니다.
combined=()
for k v ("${(@kv)A}") combined+=($v$'\0'$k)
변수는 keys
임의적이지만 일관된 순서로 values
키와 값을 포함합니다. 빈 키가 없으면 A
쓸 수 있고 값은 비슷합니다. 키를 사전식으로 정렬하고, 숫자로 정렬하려면 표시를 추가하고(이전), 오름차순으로 정렬하려면 표시를 제거합니다(이 경우 아래 첨자를 사용하여 처음 두 값을 가져올 수 있습니다).keys=(${(k)A})
keys_sorted_by_decreasing_value
n
9
10
O
[-2,-1]
Ksh93에는 위치 인수만 정렬하는 방법이 있습니다 set -s
. 이는 zsh에도 있지만 bash 4.2에는 없습니다. 값에 개행 문자나 개행 문자 앞에 정렬되는 제어 문자가 포함되어 있지 않다고 가정합니다.
keys=("${!A[@]}")
combined=()
for ((i=0; i <= ${#keys}; i++)); do combined[i]=(${A[${keys[$i]}]}$'\n'${keys[$i]}); done
set -A sorted -s "${combined[@]}"
top_combined=${sorted[${#sorted[@]}-1]} # -2 for the next-to-largest, etc.
top_key=${top_combined#*$'\n'}
이것은 모두 매우 복잡하므로 작성하기 쉬운 외부 정렬을 사용하는 것이 좋습니다. ksh 또는 bash의 키나 값에 제어 문자가 포함되어 있지 않다고 가정합니다.
IFS=$'\n'; set -f
keys_sorted_by_decreasing_value=($(
for k in "${!A[@]}"; do printf '%s\t%s\n' "${A[$k]}" "$k"; done |
sort | sed $'s/\t.*//'
))
답변2
${(kOn)A}
zsh에서는 연관 배열( ) 또는 값( ) 의 정렬된 키 목록을 얻을 수 있지만 ${(On)A}
정렬된 값 목록(AFAIK)에서 직접 얻을 수는 없지만 다음을 수행할 수 있습니다.
typeset -A assoc
assoc=(
192.168.2.2 5
192.168.3.2 1
192.168.1.1 9
192.168.8.1 9
)
ordered_keys=()
for v ("${(@nO)assoc}") ordered_keys+=("${(@k)assoc[(eR)$v]}")
즉, 값 목록()을 숫자()로 정렬하고 각 값()에 대해 O
일치하는 ey를 추가하고(정확한 일치의 경우 키가 아닌 값을 기반으로 역방향 목록을 가져옴) 추가합니다. 배열.$assoc
n
for
v
k
e
R
ordered_keys
답변3
KEY로 bash 연관 배열을 정렬하는 가장 좋은 방법은 다음과 같습니다.아니요분류하세요.
대신 KEYS 목록을 가져와 목록을 변수로 정렬한 다음 목록을 반복합니다. 예: IP 주소(키)와 호스트 이름(값) 배열이 있다고 가정합니다.
대안: KEY에서 새 목록을 생성하고, 행으로 변환하고, 정렬하고, 다시 목록으로 변환한 다음 이를 사용하여 배열을 반복합니다.
declare -A ADDR
ADDR[192.168.1.1]="host1"
ADDR[192.168.1.2]="host2"
etc...
KEYS=`echo ${!ADDR[@]} | tr ' ' '\012' | sort | tr '\012' ' '`
for KEY in $KEYS; do
VAL=${ADDR[$KEY]}
echo "KEY=[$KEY] VAL=[$VAL]"
done
답변4
"연관 배열"은 일반적으로 배열의 데이터가 실제 의미를 갖는다는 것을 의미합니다. 외부 유닉스 정렬은 이 작업에 매우 적합하며, 유닉스 정렬을 능가할 수 있는 C 프로그래머는 거의 없습니다. 특히 빅 데이터의 경우 UNIX와 셸의 모든 기능을 사용자 정의하고, 슬라이싱하고, 분기하고, 최대한 활용할 수 있습니다. 이것이 바로 많은 쉘 및 awk 플랫폼이 정렬에 신경 쓰지 않는 이유입니다.