Diberikan array string, saya ingin mengurutkan array sesuai dengan panjang setiap elemen.
Sebagai contoh...
array=(
"tiny string"
"the longest string in the list"
"middle string"
"medium string"
"also a medium string"
"short string"
)
Harus menyortir ke ...
"the longest string in the list"
"also a medium string"
"medium string"
"middle string"
"short string"
"tiny string"
(Sebagai bonus, alangkah baiknya jika daftar mengurutkan string dengan panjang yang sama, menurut abjad. Dalam contoh di atas medium string
disortir sebelum middle string
meskipun mereka memiliki panjang yang sama. Tapi itu bukan persyaratan "keras", jika terlalu mempersulit larutan).
OK jika array diurutkan di tempat (yaitu "array" dimodifikasi) atau jika array diurutkan baru dibuat.
bash
shell-script
sort
array
PJ Singh
sumber
sumber
Jawaban:
Jika string tidak mengandung baris baru, berikut ini akan berfungsi. Ini mengurutkan indeks array dengan panjang, menggunakan string sendiri sebagai kriteria pengurutan sekunder.
Perhatikan bahwa pindah ke bahasa pemrograman nyata dapat sangat menyederhanakan solusi, misalnya dalam Perl, Anda bisa saja
sumber
sorted(array, key=lambda s: (len(s), s))
array.sort { |a| a.size }
Ini membaca nilai array yang diurutkan dari subtitusi proses.
Substitusi proses berisi loop. Loop menghasilkan setiap elemen array yang diawali dengan panjang elemen dan karakter tab di antaranya.
Output dari loop diurutkan secara numerik dari terbesar ke terkecil (dan abjad jika panjang yang sama, penggunaan
-k 2r
di tempat-k 2
untuk membalik urutan abjad) dan hasil yang dikirim kecut
yang menghapus kolom dengan panjang tali.Sortir skrip uji yang diikuti oleh uji coba:
Ini mengasumsikan bahwa string tidak mengandung baris baru. Pada sistem GNU dengan yang baru-baru ini
bash
, Anda dapat mendukung baris baru yang disematkan dalam data dengan menggunakan karakter nul sebagai pemisah rekaman, bukan baris baru:Di sini, data dicetak dengan mengekor
\0
dalam lingkaran alih-alih baris baru,sort
dancut
membaca garis nul-delimited melalui-z
opsi GNU mereka danreadarray
akhirnya membaca data nul-delimited dengan-d ''
.sumber
-d '\0'
sebenarnya-d ''
karenabash
tidak dapat meneruskan karakter NUL ke perintah, bahkan bawaannya. Tapi itu dipahami-d ''
sebagai makna pembatasan pada NUL . Perhatikan bahwa Anda memerlukan bash 4.4+ untuk itu.'\0'
, bukan$'\0'
. Dan ya, itu mengkonversi (hampir persis) ke''
. Tapi itu adalah cara untuk mengkomunikasikan kepada pembaca lain niat sebenarnya menggunakan pembatas NUL.Saya tidak akan sepenuhnya mengulangi apa yang telah saya katakan tentang mengurutkan dalam bash , hanya Anda dapat mengurutkan dalam bash, tapi mungkin Anda tidak boleh. Di bawah ini adalah implementasi bash-only dari jenis penyisipan, yaitu O (n 2 ), dan hanya dapat ditoleransi untuk array kecil. Ini mengurutkan elemen array di tempat dengan panjangnya, dalam urutan menurun. Itu tidak melakukan semacam abjad sekunder.
Sebagai bukti bahwa ini adalah solusi khusus, pertimbangkan timing tiga jawaban yang ada pada berbagai ukuran array:
Choroba dan Kusalananda memiliki ide yang tepat: hitung panjang sekali dan gunakan utilitas khusus untuk menyortir dan memproses teks.
sumber
Peretasan? (kompleks) dan cara satu baris yang cepat untuk mengurutkan array menurut panjangnya
( aman untuk baris baru dan array jarang):
Pada satu baris:
Saat eksekusi
sumber
Ini juga menangani elemen array dengan baris baru di dalamnya; ini bekerja dengan
sort
hanya melewati panjang dan indeks setiap elemen. Ini harus bekerja denganbash
danksh
.Jika elemen-elemen dengan panjang yang sama juga harus diurutkan secara leksikografis, loop dapat diubah seperti ini:
Ini juga akan diteruskan ke
sort
string (dengan baris baru berubah menjadi spasi), tetapi mereka akan tetap disalin dari sumber ke array tujuan dengan indeks mereka. Dalam kedua contoh,$(...)
hanya akan melihat garis yang berisi angka (dan/
karakter dalam contoh pertama), sehingga tidak akan tersandung oleh karakter globbing atau spasi di string.sumber
$(...)
substitusi perintah hanya melihat indeks (daftar angka yang dipisahkan oleh baris baru), karenacut -d' ' -f1
pengurutan setelahnya. Ini dapat dengan mudah ditunjukkan olehtee /dev/tty
pada akhir$(...)
.cut
.${!in[@]}
atau${#in[i]}/$i
ekspansi variabel karena mereka hanya berisi digit yang tidak tunduk pada ekspansi glob danunset IFS
akan mengatur ulangIFS
ruang, tab, baris baru. Bahkan, mengutipnya akan berbahaya , karena akan memberikan kesan yang salah bahwa mengutip seperti itu bermanfaat dan efektif, dan bahwa pengaturanIFS
dan / atau penyaringan outputsort
pada contoh kedua dapat dengan aman dihilangkan dengan aman.in
berisi"testing * here"
danshopt -s nullglob
diatur sebelum loop.Dalam kasus beralih ke
zsh
adalah opsi, cara hackish sana (untuk array berisi urutan byte):zsh
memungkinkan menentukan perintah sortir untuk ekspansi glob melalui kualifikasi glob. Jadi di sini, kami menipu untuk melakukannya untuk array sewenang-wenang dengan globbing on/
, tetapi mengganti/
dengan elemen array (e'{reply=("$array[@]")}'
) dan kemudian secaran
kasar rdero
(terbalik dengan huruf besarO
) elemen berdasarkan panjangnya (Oe'{REPLY=$#REPLY}'
).Perhatikan bahwa ini didasarkan pada panjangnya jumlah karakter. Untuk jumlah byte, atur lokal ke
C
(LC_ALL=C
).bash
Pendekatan 4.4+ lainnya (dengan asumsi array tidak terlalu besar):(itu panjang dalam byte ).
Dengan versi yang lebih lama
bash
, Anda selalu dapat melakukan:(yang juga akan bekerja dengan
ksh93
,zsh
,yash
,mksh
).sumber