Zsh có một cách tích hợp để sắp xếp danh sách. Tuy nhiên, tôi không nghĩ có cách sắp xếp các giá trị trong khi vẫn giữ mối tương quan với các khóa bằng cờ mở rộng tham số và cờ phụ , điều đó có nghĩa là cần một vòng lặp rõ ràng. Giả sử rằng các giá trị của bạn không chứa ký tự null, bạn có thể tạo một mảng chứa các giá trị và khóa được nối với một ký tự null ở giữa và sắp xếp nó.
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]}")
EDIT bởi @sch: 4 dòng đầu tiên có thể được đơn giản hóa thành
combined=()
for k v ("${(@kv)A}") combined+=($k$'\0'$v)
Các biến keys
và values
chứa các khóa và giá trị A
theo thứ tự tùy ý nhưng nhất quán. Bạn có thể viết keys=(${(k)A})
nếu không có khóa trống và tương tự cho các giá trị. keys_sorted_by_decreasing_value
sắp xếp các khóa theo từ vựng, thêm n
cờ để sắp xếp số ( 9
trước 10
) và loại bỏ O
nếu bạn muốn sắp xếp theo thứ tự tăng dần (trong trường hợp đó có thể thu được hai giá trị trên cùng với chỉ mục [-2,-1]
).
Ksh93 có cách chỉ sắp xếp các tham số vị trí, với set -s
; Điều này cũng tồn tại trong zsh nhưng không có trong bash 4.2. Giả sử giá trị của bạn không chứa dòng mới hoặc ký tự điều khiển sắp xếp trước dòng mới:
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'}
Đây là tất cả khá phức tạp, vì vậy bạn cũng có thể đi cho sắp xếp bên ngoài, dễ viết hơn nhiều. Giả sử rằng cả khóa và giá trị đều không chứa ký tự điều khiển, trong ksh hoặc 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.*//'
))
bash
để dễ dàng thực hiện. Bạn đang cố làm gì vậy?