quindi mi sto occupando di problemi di media della colonna
Ho diverse colonne di numeri,
1 2 3 4 5
2 3 4 5 6
8 4 5 6 7
9 8 7 6 5
1 9 9 9 2
Quello che voglio fare è prendere una media di ogni colonna in modo che cedano
4 5 5 6 5
La parte sommatoria non è un problema, sono in grado di ottenere la somma di ogni colonna, ma in qualche modo sto avendo problemi nel conteggio del numero di colonne (variabile $ x) Ecco il mio codice
while read line; do
x = 0
read -a array <<< "$line"
for i in "${!array[@]}"
do
column[${i}]=$((${column[${i}]}+${array[$i]}))
((x++))
done
done < $TMP
for sum in ${column[@]}
do
average=`expr $sum / $x`
remainder=`expr $sum % $x`
mult=`expr $remainder * 10`
fracvalue=`expr $mult / $x`
echo $x
echo $average
echo $sum
echo $remainder
echo $mult
echo $fracvalue
done
Le ultime righe sono per i miei testscopi, qui $ X continua a mostrare 1 invece di 5. Ecco perché svuota tutte le altre variabili Qualcuno sa dov'è il difetto in questo codice? Apprezzo davvero il tuo aiuto. Grazie
risposte:
0 per risposta № 1Un altro approccio:
#!/bin/bash
declare -ia sum # declare array of integers
declare -i lines=0 # declare integer to count lines
# read file to array and sum values
while read -ra array; do
for ((i=0; i<${#array[@]};i++)); do
sum[$i]+=${array[$i]}
done
lines+=1
done < file
# print averages
for ((j=0; j<$i;j++)); do
echo -n "$((${sum[$j]}/$lines)) "
done
Produzione:
4 5 5 6 5
0 per risposta № 2
Il problema è nella linea
x = 0
dovrebbe essere
x=0
e fare ((x+1))
come let "x+=1"
dovrebbe funzionare.
0 per risposta № 3
Forse il tuo file non ha lo stesso numero di righe in ogni colonna.
while read line; do
read -a array <<< "$line"
for i in "${!array[@]}"
do
column[${i}]=$((${column[${i}]}+${array[$i]}))
((x[${i}]++))
done
done < $TMP
for i in ${!column[@]}
do
sum=${column[$i]}
x=${x[${i}]}
#your calcul
done
0 per risposta № 4
Il problema iniziale, a parte alcune peculiarità della sintassi, era il ripristino di x
su ciascun read
che ti ha fatto perdere il conteggio delle righe. Inoltre, il tuo array è un indicizzato array, non un associativo array.
Fare le piccole regolazioni e declare
all'inizio delle variabili (per suggerire a bash sono numeri interi o matrici), funziona come pianificato. Nota: non c'è bisogno di a stringa here per assegnare l'array, basta usare la normale sintassi dell'array. Inoltre, per gli array indicizzati, non è necessario dereferenziare la variabile all'interno [ ]
, semplicemente ${array[i]}
è ok.
Mentre l'uso di expr
va bene (vecchio, lento, ma portatile e fine), è possibile utilizzare la sintassi aritmetica bash per i calcoli dei parametri alla fine. (hai già matrici). Infine, è meglio servirne l'inizializzazione column[$i]=0
sul primo ciclo di lettura. Puoi farlo con una semplice bandiera:
#!/bin/bash
declare -i ncols=0
declare -i x=0
declare -a column
while read -r line; do
array=( $line )
[ $ncols -eq 0 ] && ncols=${#array[@]}
for ((i = 0; i < ncols; i++))
do
[ $x -eq 0 ] && column[$i]=0
column[$i]=$(( ${column[i]} + ${array[i]}))
done
((x++))
done < "$1"
for sum in ${column[@]}
do
average=`expr $sum / $x`
remainder=`expr $sum % $x`
mult=`expr $remainder * 10`
fracvalue=`expr $mult / $x`
echo $x
echo $average
echo $sum
echo $remainder
echo $mult
echo $fracvalue
done
exit 0
Produzione
$ bash colavg.sh dat/colavg.txt
5
4
21
1
10
2
5
5
26
1
10
2
5
5
28
3
30
6
5
6
30
0
0
0
5
5
25
0
0
0