/ / Oblicz medianę w wielu wierszach - bash

Oblicz medianę w wielu wierszach - bash

Mam nazwę pliku liczby, po prostu zawierają pęczek liczb losowych

1     2     3
7     5     9
2     2     9
5     4     5
7     2     6

Muszę stworzyć skrypt, który znajdzie medianę dla każdego wiersza, a oto mój kod:

while read -a row
do
for i in "${row[@]}"
do

length=`expr ${#row[@]} % 2`
if [ $length -ne 0 ] ; then
mid=`expr ${#row[@]} / 2`
echo ${row[middle]}
elif [ $length -eq 0 ] ; then
val1=`expr ${#row[@]} / 2`
val2=`expr (${$row[@]} / 2) + 1`
mid=`expr ($val1 + $val2) / 2`
echo $mid
done | sort -n
done < numbers

Jednak to nie działa, zamiast tego pokazuje błąd, jaki błąd popełniłem w tym kodzie? Również nadal nie wiem, gdzie jest właściwy sposób umieszczenia sort -n ponieważ musi najpierw zostać posortowane przed obliczeniem mediany, prawda?

Odpowiedzi:

1 dla odpowiedzi № 1

Bash może wykonywać tylko arytmetykę całkowitą, potrzebujesz narzędzia takiego jak bc obliczyć średnią:

#!/bin/bash
while read -a n ; do
n=($(IFS=$"n" ; echo "${n[*]}" | sort -n))
len=${#n[@]}
if (( len % 2 )) ; then
echo ${n[ len / 2 ]}
else
bc -l <<< "scale=1; (${n[ len / 2 - 1 ]} + ${n[ len / 2 ]}) / 2"
fi
done

Prawdopodobnie sięgnę do języka wyższego poziomu, np. Perl:

#!/usr/bin/perl
use warnings;
use strict;

while (<>) {
my @n = sort { $a <=> $b } split;
print @n % 2 ? $n[ @n / 2 ]
: ($n[ @n / 2 - 1 ] + $n[ @n / 2 ]) / 2,
"n";
}

0 dla odpowiedzi nr 2

Po prostu musiałem to zszokować, dla zabawy.

Zauważ, że nie używam if ale ułamki indeksów.

awk "{
split($0,a)    # create array a from input line
asort(a,b)     # sort array into array b (gnu awk specific)
# add twice the median, or around the median and divide by 2
print ( b[int(NF/2+0.7)] + b[int(NF/2+1.2)] )/2
}" numbers

Skrócone (67 znaków):

awk "{split($0,a);asort(a,b);print(b[int(NF/2+0.7)]+b[int(NF/2+1.2)])/2}" numbers

66 znaków w golfa :-)

awk "{split($0,a);asort(a,b);$0=(b[int(NF/2+0.7)]+b[int(NF/2+1.2)])/2}1" numbers