Untuk tugas saya harus menulis fungsi yang mencetak jumlah angka genap ketika disediakan dengan urutan angka.
Saya menggunakan potongan kode yang saya gunakan untuk tugas sebelumnya (untuk mencetak 1
ketika nomor genap dan 0
ketika nomor itu ganjil)
Masalah saya sekarang adalah fungsi saya terus mencetak 0
. Apa yang saya lakukan salah?
Ini skrip saya:
#!/usr/bin/bash
# File: nevens.sh
# Write a function called nevens which prints the number of even numbers when provided with a sequence of numbers.
# Check: input nevens 42 6 7 9 33 = output 2
function nevens {
local sum=0
for element in $@
do
let evencheck=$(( $# % 2 ))
if [[ $evencheck -eq 0 ]]
then
let sum=$sum+1
fi
done
echo $sum
}
Jawaban:
Anda lupa mengganti
$#
dengan ($
)element
difor
loop:Sekarang untuk menguji fungsinya:
sumber
@dabut telah menemukan masalah inti, saya akan memberikan beberapa tinjauan kode:
/usr/bin/bash
di Ubuntu. Ini/bin/bash
.Ada baiknya Anda mendeklarasikan
sum
local
, dan menghindari mencemari namespace variabel di luar fungsi. Selain itu, Anda dapat mendeklarasikannya sebagai variabel integer menggunakan-i
opsi:Selalu kutip variabel Anda (dan parameter)! Tidak perlu dalam skrip ini, tetapi kebiasaan yang sangat baik untuk masuk:
Yang mengatakan, Anda dapat menghilangkan di
in "$@"
sini:Ketika
in <something>
tidak diberikan,for
loop secara implisit loop atas argumen. Ini dapat menghindari kesalahan seperti melupakan kutipan.Tidak perlu menghitung dan kemudian memeriksa hasilnya. Anda dapat langsung melakukan perhitungan di
if
:(( ... ))
adalah konteks aritmatika . Ini lebih berguna daripada[[ ... ]]
untuk melakukan pemeriksaan aritmatika, dan selain itu Anda dapat menghilangkan$
variabel sebelumnya (yang membuatnya lebih mudah dibaca, IMHO).Jika Anda memindahkan bagian pemeriksa ke fungsi yang terpisah, itu mungkin meningkatkan keterbacaan dan penggunaan kembali:
sumber
sum=$((sum + 1 - element % 2))
.&1
untuk memeriksa bit rendah jika itu lebih mudah dibaca untuk Anda). Tapi kita bisa membuatnya lebih mudah dibaca:sum=$((sum + !(element&1) ))
menggunakan boolean inverse sebagai gantinya+1 - condition
. Atau hitung saja unsur-unsur aneh dengan((odd += element&1))
, dan pada akhirnya dicetak denganecho $(($# - element))
, karenaeven = total - odd
.local -i
dansum++
.Saya tidak yakin apakah Anda terbuka untuk solusi lain. Juga saya tidak tahu apakah Anda dapat menggunakan utilitas eksternal, atau apakah Anda murni terbatas pada bash builtin. Jika Anda dapat menggunakan
grep
, misalnya, fungsi Anda bisa menjadi jauh lebih sederhana:Ini menempatkan setiap integer input pada barisnya sendiri, dan kemudian digunakan
grep
untuk menghitung garis yang berakhir pada angka genap.Pembaruan - @PeterCordes menunjukkan bahwa kita bahkan dapat melakukan ini tanpa grep - hanya bash murni, selama daftar input berisi bilangan bulat yang terbentuk dengan baik (tanpa titik desimal):
Ini berfungsi dengan membuat daftar yang dipanggil
evens
dengan menyaring semua peluang, lalu mengembalikan panjang daftar itu.sumber
3.0
sebagai angka genap; pertanyaannya tidak tepat tentang bagaimana bentuk angka-angka itu${/%/}
pada@
array untuk memerlukan kecocokan di akhir string, di dalam inisialisasi array. Cetak hitungan. Sebagai satu-kapal untuk mendefinisikan dan menjalankannya:foo(){ evens=( ${@/%*[13579]/} ); echo "${#evens[@]} even numbers"; printf "%s\n" "${evens[@]}"; }; foo 135 212 325 3 6 3 4 5 9 7 2 12310
. Termasuk sebenarnya mencetak daftar untuk debugging. Cetakan5 even numbers 212 6 4 2 12310
(pada baris sep.)grep
sebenarnya lebih cepat daripadabash
. Hmm, saya bertanya-tanya apakah ada pertanyaan codegolf di mana saya bisa memposting fungsi bash itu: P