在一行BASH命令中获取未排序数组的中位数

3

我找不到简单的实现方法来查找数组的中位数。在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的一行解决方案吗? - Jose Ricardo Bustos M.
4
排好序的数组的中位数在中间位置或附近;未排序的数组的中位数可能出现在数组的任何位置 - chepner
1
将此答案的第二行粘贴到您的函数顶部... https://dev59.com/LWs05IYBdhLWcg3wG-RR#7442658 - Mark Setchell
2个回答

4
我认为你想要的是这样的内容:

我认为您想要类似于这样的东西:

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

要处理浮点数,请将(( val=(${arr[j]} + ${arr[k]})/2 ))这一行更改为val=$(echo "scale=2;(${arr[j]}" + "${arr[k]})"/2|bc -l) - jaygooby

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

你不需要使用sed命令。只需在bc调用中传递一个scale值;echo "(1.1+2)/2"|bc -l = 1.55000000000000000000 echo "scale=2;(1.1+2)/2"|bc -l = 1.55 - jaygooby
@jaygooby:你能把这个修改加入到答案中吗? - einpoklum

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接