2017-01-19 3 views
2

Ich konnte keine einfachen Implementierungen finden, um den Median eines Arrays zu finden. Wie kann dies Bash sein, ohne das Rad neu zu erfinden?Erhalten Median der unsortierten Array in einer Zeile von BASH

Wenn dies derzeit mit:

median() { 
    arr=$1 
    nel=${#arr[@]} 
    if (($nel % 2 == 1)); then  # Odd number of elements 
    val="${arr[ $(($nel/2)) ]}" 
    else       # Even number of elements 
    val="$(((arr[$((nel/2))] + arr[$((nel/2-1))])/2))" 
    fi 
    printf "%d\n" "$val" 
} 

Aus irgendeinem Grund Rückkehr Ich kann immer noch nicht herausfinden, ist es falsche Werte, und es scheint zu kompliziert für etwas so einfach. Ich habe das Gefühl, dass es einen Weg geben muss, dies in einer Linie zu tun.

+1

Ehrlich gesagt, sehe ich in diesem Code nichts Kompliziertes ... Willst du eine Ein-Zeilen-Lösung mit reinem 'bash'? –

+4

Der Median eines sortierten Arrays liegt bei oder in der Nähe der Mitte; Der Median eines unsortierten Arrays könnte * überall * im Array auftreten. – chepner

+1

Fügen Sie die zweite Zeile dieser Antwort in der Nähe der Spitze Ihrer Funktion ein ... http://stackoverflow.com/a/7442658/2836621 –

Antwort

2

Ich glaube, Sie so etwas wie dies wollen:

#!/bin/bash 
median() { 
    arr=($(printf '%d\n' "${@}" | sort -n)) 
    nel=${#arr[@]} 
    if (($nel % 2 == 1)); then  # Odd number of elements 
    val="${arr[ $(($nel/2)) ]}" 
    else       # Even number of elements 
    ((j=nel/2)) 
    ((k=j-1)) 
    ((val=(${arr[j]} + ${arr[k]})/2)) 
    fi 
    echo $val 
} 

median 1 
median 2 50 1 
median 1000 1 40 50 

Beispielausgabe

1 
2 
45 
0

Dies sowohl für Integral- und fraktionierte Daten arbeiten sollten:

#!/bin/bash 

median() { 
    declare -a data=("${!1}") 
    IFS=$'\n' sorted_data=($(sort <<<"${data[*]}")) 
    local num_elements=${#sorted_data[@]} 
    if (($num_elements % 2 == 1)); then  # Odd number of elements 
     ((middle=$num_elements/2)) 
     val="${sorted_data[ $(($num_elements/2)) ]}" 
    else       # Even number of elements 
     ((before_middle=$num_elements/2 - 1)) 
     ((after_middle=$num_elements/2)) 
     val=$(echo "(${sorted_data[$before_middle]} + ${sorted_data[$after_middle]})/2" | bc -l) 
    fi 
    # remove trailing zeros 
    echo $val | sed -r 's/\.([0-9]*[1-9])0*$/\.\1/; s/\.0*$//;' 
} 


median 1 
median 2 50 1 
median 1000 1 40 50 
median 1.5 2.5 
median 0.3 0.6 0.9 

ergibt:

1 
2 
45 
2 
0.6 
Verwandte Themen