2011-11-21 53 views
16

tôi nhận được kết quả như sau:Bash mảng kết hợp sắp xếp

Pushkin - 100500 
Gogol - 23 
Dostoyevsky - 9999 

Đó là kết quả của kịch bản sau đây:

for k in "${!authors[@]}" 
do 
    echo $k ' - ' ${authors["$k"]} 
done 

Tất cả tôi muốn là để có được kết quả như thế này:

Pushkin - 100500 
Dostoyevsky - 9999 
Gogol - 23 

có nghĩa là các khóa trong mảng liên kết phải được sắp xếp theo giá trị. Có một phương pháp dễ dàng để làm như vậy?

Trả lời

17

Bạn có thể dễ dàng sắp xếp kết quả của bạn, trong thứ tự giảm dần số của lĩnh vực thứ 3:

for k in "${!authors[@]}" 
do 
    echo $k ' - ' ${authors["$k"]} 
done | 
sort -rn -k3 

Xem loại (1) để biết thêm về lệnh sort. Điều này chỉ sắp xếp các dòng đầu ra; Tôi không biết bất kỳ cách nào để sắp xếp một mảng trực tiếp trong bash.

Tôi cũng không thể thấy cách bên trên có thể cung cấp cho bạn tên ("Pushkin" et al.) Làm khóa mảng. Trong bash, các khóa mảng luôn là số nguyên.

+6

Bash 4.0 bổ sung thêm mảng kết hợp phím có thể là chuỗi. –

+2

Tôi sẽ ... bạn nói đúng. Nó chỉ cần 'khai báo -A tác giả'. –

+1

Giải pháp của bạn hoạt động. Theo như tôi hiểu, nó chỉ sắp xếp các chuỗi đầu ra, không phải nội dung của mảng kết hợp, nhưng dù sao, đầu ra được tạo ra là những gì tôi cần. – Graf

7

Hoặc bạn có thể sắp xếp các chỉ số và sử dụng danh sách sắp xếp các chỉ số để lặp qua mảng:

authors_indexes=(${!authors[@]}) 
IFS=$'\n' authors_sorted=($(echo -e "${authors_indexes[@]/%/\n}" | sed -r -e 's/^ *//' -e '/^$/d' | sort)) 

for k in "${authors_sorted[@]}"; do 
    echo $k ' - ' ${authors["$k"]} 
done 
+0

Boo, hiss re: 'echo -e'. Hãy xem xét 'printf '% s \ n'" $ {authors_indexes [@]} "' để mở rộng một mảng thành nhiều dòng theo cách không phụ thuộc vào vi phạm của POSIX sh (không chỉ là phần mở rộng, mà là vi phạm thực tế: Bất kỳ đối số nào khác với '-n' được yêu cầu để in văn bản của nó, trừ khi nó có dấu gạch chéo ngược hoặc' -n' là hiện diện, trong đó hành vi trường hợp hoàn toàn được thực hiện xác định). Hoặc 'printf '% s \ 0'" $ {array [@]} "' để mở rộng mảng dưới dạng chuỗi NUL-delimit, do đó theo cách thức hoạt động ngay cả khi bạn có dòng mới trong khóa của bạn (trong đó * là * hợp pháp). –

+0

... xem http://pubs.opengroup.org/onlinepubs/009695399/utilities/echo.html, đặc biệt là phần SỬ DỤNG ỨNG DỤNG. –

2

Mở rộng câu trả lời từ @AndrewSchulman, sử dụng -rn như một tùy chọn sắp xếp toàn cầu đảo ngược tất cả các cột. Trong ví dụ này, các tác giả có cùng giá trị mảng kết hợp sẽ được xuất theo thứ tự ngược lại của tên.

Ví dụ

declare -A authors 
authors=([Pushkin]=10050 [Gogol]=23 [Dostoyevsky]=9999 [Tolstoy]=23) 

for k in "${!authors[@]}" 
do 
    echo $k ' - ' ${authors["$k"]} 
done | sort -rn -k3 

chí đầu ra

 
Pushkin - 10050 
Dostoyevsky - 9999 
Tolstoy - 23 
Gogol - 23 
Tùy chọn để phân loại các cột cụ thể có thể được cung cấp sau khi specifier cột. tức là sort -k3rn

Lưu ý rằng các phím có thể được chỉ định là nhịp. Ở đây -k3 xảy ra là tốt bởi vì nó là nhịp cuối cùng, nhưng chỉ sử dụng cột 3 (trong trường hợp thêm cột), nó phải được chỉ định là -k3,3, Tương tự như sắp xếp theo cột ba theo thứ tự giảm dần, và sau đó cột một thứ tự tăng dần (mà có lẽ là những gì được mong muốn trong ví dụ này):

declare -A authors 
authors=([Pushkin]=10050 [Gogol]=23 [Dostoyevsky]=9999 [Tolstoy]=23) 
for k in "${!authors[@]}" 
do 
    echo $k ' - ' ${authors["$k"]} 
done | sort -k3,3rn -k1,1 

chí đầu ra

 
Pushkin - 10050 
Dostoyevsky - 9999 
Gogol - 23 
Tolstoy - 23 

Các vấn đề liên quan