Jawaban:
Saya telah menjawab pertanyaan seperti yang tertulis, dan kode ini membalikkan array. (Mencetak elemen dalam urutan terbalik tanpa membalikkan array hanyalah sebuah for
loop menghitung mundur dari elemen terakhir ke nol.) Ini adalah algoritma "swap first and last" standar.
array=(1 2 3 4 5 6 7)
min=0
max=$(( ${#array[@]} -1 ))
while [[ min -lt max ]]
do
# Swap current first and last elements
x="${array[$min]}"
array[$min]="${array[$max]}"
array[$max]="$x"
# Move closer
(( min++, max-- ))
done
echo "${array[@]}"
Ini berfungsi untuk array dengan panjang ganjil dan genap.
Pendekatan lain yang tidak konvensional:
#!/bin/bash
array=(1 2 3 4 5 6 7)
f() { array=("${BASH_ARGV[@]}"); }
shopt -s extdebug
f "${array[@]}"
shopt -u extdebug
echo "${array[@]}"
Keluaran:
7 6 5 4 3 2 1
Jika extdebug
diaktifkan, array BASH_ARGV
berisi semua parameter posisi dalam fungsi dengan urutan terbalik.
Pendekatan tidak konvensional (semuanya tidak murni bash
):
jika semua elemen dalam array hanya satu karakter (seperti dalam pertanyaan) Anda dapat menggunakan rev
:
echo "${array[@]}" | rev
jika tidak:
printf '%s\n' "${array[@]}" | tac | tr '\n' ' '; echo
dan jika Anda dapat menggunakan zsh
:
echo ${(Oa)array}
tac
, sebagai lawan dari cat
cukup baik untuk diingat, TERIMA KASIH!
rev
, saya perlu menyebutkan bahwa rev
tidak akan berfungsi dengan benar untuk angka dengan dua digit. Misalnya elemen array 12
menggunakan rev akan dicetak sebagai 21
. Cobalah ;-)
Jika Anda benar-benar ingin membalikkan dalam array lain:
reverse() {
# first argument is the array to reverse
# second is the output array
declare -n arr="$1" rev="$2"
for i in "${arr[@]}"
do
rev=("$i" "${rev[@]}")
done
}
Kemudian:
array=(1 2 3 4)
reverse array foo
echo "${foo[@]}"
Memberi:
4 3 2 1
Ini harus menangani kasus dengan benar di mana indeks array tidak ada, misalnya Anda miliki array=([1]=1 [2]=2 [4]=4)
, dalam hal ini pengulangan dari 0 ke indeks tertinggi dapat menambahkan elemen tambahan, kosong.
shellcheck
mencetak dua peringatan: array=(1 2 3 4)
<-- SC2034: array appears unused. Verify it or export it.
dan untuk:echo "${foo[@]}"
<-- SC2154: foo is referenced but not assigned.
declare
baris.
declare -n
tampaknya tidak berfungsi dalam versi bash sebelum 4.3.
Untuk menukar posisi array di tempat (bahkan dengan array jarang) (sejak bash 3.0):
#!/bin/bash
# Declare an sparse array to test:
array=([5]=101 [6]=202 [10]=303 [11]=404 [20]=505 [21]=606 [40]=707)
echo "Initial array values"
declare -p array
swaparray(){ local temp; temp="${array[$1]}"
array[$1]="${array[$2]}"
array[$2]="$temp"
}
ind=("${!array[@]}") # non-sparse array of indexes.
min=-1; max="${#ind[@]}" # limits to one before real limits.
while [[ min++ -lt max-- ]] # move closer on each loop.
do
swaparray "${ind[min]}" "${ind[max]}" # Exchange first and last
done
echo "Final Array swapped in place"
declare -p array
echo "Final Array values"
echo "${array[@]}"
Pada eksekusi:
./script
Initial array values
declare -a array=([5]="101" [6]="202" [10]="303" [11]="404" [20]="505" [21]="606" [40]="707")
Final Array swapped in place
declare -a array=([5]="707" [6]="606" [10]="505" [11]="404" [20]="303" [21]="202" [40]="101")
Final Array values
707 606 505 404 303 202 101
Untuk bash yang lebih lama, Anda perlu menggunakan loop (dalam bash (sejak 2.04)) dan menggunakan $a
untuk menghindari ruang trailing:
#!/bin/bash
array=(101 202 303 404 505 606 707)
last=${#array[@]}
a=""
for (( i=last-1 ; i>=0 ; i-- ));do
printf '%s%s' "$a" "${array[i]}"
a=" "
done
echo
Untuk bash sejak 2.03:
#!/bin/bash
array=(101 202 303 404 505 606 707)
last=${#array[@]}
a="";i=0
while [[ last -ge $((i+=1)) ]]; do
printf '%s%s' "$a" "${array[ last-i ]}"
a=" "
done
echo
Juga (menggunakan operator negasi bitwise) (sejak bash 4.2+):
#!/bin/bash
array=(101 202 303 404 505 606 707)
last=${#array[@]}
a=""
for (( i=0 ; i<last ; i++ )); do
printf '%s%s' "$a" "${array[~i]}"
a=" "
done
echo
Jelek, tidak bisa dipelihara, tapi hanya satu kalimat:
eval eval echo "'\"\${array['{$((${#array[@]}-1))..0}']}\"'"
eval eval echo "'\"\${array[-'{1..${#array[@]}}']}\"'"
.
ind=("${!array[@]}");eval eval echo "'\"\${array[ind[-'{1..${#array[@]}}']]}\"'"
Meskipun saya tidak akan mengatakan sesuatu yang baru dan saya juga akan menggunakan tac
untuk membalikkan array, saya pikir itu akan layak untuk disebutkan di bawah solusi single line menggunakan bash versi 4.4:
$ read -d'\n' -a array < <(printf '%s\n' "${array[@]}" |tac)
Pengujian:
$ array=(1 2 3 4 5 6 10 11 12)
$ echo "${array[@]}"
1 2 3 4 5 6 10 11 12
$ read -d'\n' -a array < <(printf '%s\n' "${array[@]}"|tac)
$ echo "${array[@]}"
12 11 10 6 5 4 3 2 1
Ingat bahwa nama var di dalam read adalah nama sebagai array asli, jadi tidak ada array pembantu yang diperlukan untuk penyimpanan temp.
Implementasi alternatif dengan menyesuaikan IFS:
$ IFS=$'\n' read -d '' -a array < <(printf '%s\n' "${array[@]}"|tac);declare -p array
declare -a array=([0]="12" [1]="11" [2]="10" [3]="6" [4]="5" [5]="4" [6]="3" [7]="2" [8]="1")
PS: Saya pikir solusi di atas tidak akan berfungsi dalam bash
versi di bawah 4.4
karena read
implementasi fungsi bash builtin yang berbeda .
IFS
Versi bekerja tetapi juga mencetak: declare -a array=([0]="1" [1]="2" [2]="3" [3]="4" [4]="5" [5]="6" [6]="10" [7]="11" [8]="12")
. Menggunakan bash 4.4-5
. Anda harus menghapus ;declare -p array
di akhir baris pertama, lalu bekerja ...
declare -p
hanyalah cara cepat untuk membuat bash mencetak array asli (indeks dan konten). Anda tidak perlu declare -p
perintah ini di skrip asli Anda. Jika ada yang salah dalam tugas array Anda, Anda bisa berakhir dalam kasus yang ${array[0]}="1 2 3 4 5 6 10 11 12"
= semua nilai disimpan dalam indeks yang sama - menggunakan gema Anda tidak akan melihat perbedaan. Untuk pencetakan array cepat menggunakan declare -p array
akan mengembalikan Anda indeces array asli dan nilai yang sesuai di setiap indeks.
read -d'\n'
metode ini tidak berhasil untuk Anda?
read -d'\n'
bekerja dengan baik.
Untuk membalikkan array sewenang-wenang (yang mungkin mengandung sejumlah elemen dengan nilai apa pun):
Dengan zsh
:
array_reversed=("${(@Oa)array}")
Dengan bash
4.4+, mengingat bahwa bash
variabel tidak dapat mengandung byte NUL, Anda dapat menggunakan GNU tac -s ''
pada elemen yang dicetak sebagai catatan dibatasi NUL:
readarray -td '' array_reversed < <(
((${#array[@]})) && printf '%s\0' "${array[@]}" | tac -s '')
POSIXly, untuk membalikkan susunan shell POSIX ( $@
, terbuat dari $1
, $2
...):
code='set --'
n=$#
while [ "$n" -gt 0 ]; do
code="$code \"\${$n}\""
n=$((n - 1))
done
eval "$code"
Solusi bash murni, akan berfungsi sebagai one-liner.
$: for (( i=${#array[@]}-1; i>=0; i-- ))
> do rev[${#rev[@]}]=${array[i]}
> done
$: echo "${rev[@]}"
7 6 5 4 3 2 1
rev+=( "${array[i]}" )
tampak lebih sederhana.
Anda juga dapat mempertimbangkan untuk menggunakan seq
array=(1 2 3 4 5 6 7)
for i in $(seq $((${#array[@]} - 1)) -1 0); do
echo ${array[$i]}
done
di freebsd Anda dapat menghilangkan -1 parameter kenaikan:
for i in $(seq $((${#array[@]} - 1)) 0); do
echo ${array[$i]}
done
array=(1 2 3 4 5 6 7)
echo "${array[@]} " | tac -s ' '
Atau
array=(1 2 3 4 5 6 7)
reverse=$(echo "${array[@]} " | tac -s ' ')
echo ${reverse[@]}
7 6 5 4 3 2 1
$ tac --version
tac (GNU coreutils) 8.28
tac
telah disebutkan: unix.stackexchange.com/a/412874/260978 , unix.stackexchange.com/a/467924/260978 , unix.stackexchange.com/a/413176/260978