2017-01-19 5 views
2

Я не смог найти каких-либо простых реализаций для поиска медианы массива. Как это сделать, это bash, не изобретая колесо?Получить медиану несортированного массива в одной строке BASH

Если в настоящее время с помощью этого:

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" 
} 

почему я до сих пор не могу понять, что возвращается неправильные значения, и это кажется слишком сложным для чего-то так просто. Я чувствую, что должен быть способ сделать это в одной строке.

+1

Честно говоря, я не вижу ничего сложного в этом коде ...... Вам нужно однострочное решение, используя чистые 'bash'? –

+4

Медиана сортированного массива находится посередине или рядом с ней; медиана несортированного массива может иметь место * где угодно * в массиве. – chepner

+1

Вставьте вторую строку этого ответа в верхней части вашей функции ... http://stackoverflow.com/a/7442658/2836621 –

ответ

2

Я думаю, что вы хотите что-то вроде этого:

#!/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 

Пример вывод

1 
2 
45 
0

Это должно работать как для целочисленных и дробных данных:

#!/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 

выходов:

1 
2 
45 
2 
0.6 
Смежные вопросы