【问题标题】:Get median from string of values从值字符串中获取中位数
【发布时间】:2016-03-27 20:57:58
【问题描述】:

我需要找到保存在字符串中的值的中位数。我必须在没有任何额外临时文件的情况下在 bash 中实现它,并且我不能使用 awk。

我有这个字符串保存在$string:

85 13 4 45 1111 89 87 66 1 5 2 51 13 66 98 50 20 14 18 16 31 21 5175 12

首先,我需要像这样对这些值进行排序:

1 2 4 5 12 13 13 14 16 18 20 21 31 45 50 51 66 66 85 87 89 98 1111 5175

然后我需要找到这些值的中位数

(21+31) / 2 = 26

我怎样才能做到这一点? bash中是否有任何有效的方法或命令可用?

我的想法:

要对值进行排序,我可以使用sort,但我不确定如何强制它对字符串中的值进行排序,因为它使用的是 FILE。

我不知道如何达到中位数,所以至少我会很感激。

【问题讨论】:

    标签: linux string bash sorting median


    【解决方案1】:

    要将字符串中的数字放入已排序的数组中,您可以将它们分别打印在单独的行上,通过管道传送到sort -n,然后使用mapfile 读入数组:

    string='85 13 4 45 1111 89 87 66 1 5 2 51 13 66 98 50 20 14 18 16 31 21 5175 12'
    mapfile -t arr < <(for num in $string; do echo "$num"; done | sort -n)
    

    -t 选项从每个值中删除换行符。请注意,您不能通过管道连接到 mapfile,因为那将位于子 shell 中,而 arr 之后将为空。

    引用变量通常是个好主意,但在这种情况下,我们依赖分词,不能引用$string

    现在,对于中位数,有两种选择:

    • 有奇数个数组元素,我们只需要中间元素的值。
    • 有偶数个数组元素,我们需要两个中间元素的平均值。

    数组元素的数量是${#arr[@]},所以我们可以检查一下然后决定做什么:

    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——我们从三除以二的整数除法得到。对于偶数个元素,比如 4 个,我们想要索引 1 和 2 处的元素,我们通过将 4 除以 2 得到较高索引并从中减去 1 得到较低索引。

    如果两个元素加起来不是偶数,结果将向下取整。如果这还不够好,我们可以检查数字是否为奇数并手动将.5 添加到结果中,或者我们可以使用bc 进行计算。考虑:

    $ echo $(( 11/2 ))
    5
    $ bc <<< 'scale=1; 11/2'
    5.5
    

    【讨论】:

      【解决方案2】:

      您可以使用如下命令:

      str="85 13 4 45 1111 89 87 66 1 5 2 51 13 66 98 50 20 14 18 16 31 21 5175 12"
      count=$(echo $str | wc -w)
      arr=($(echo $str | tr " " "\n" | sort -n ))
      #echo ${arr[*]}
      
      if [[ $(( $count % 2 )) == 0 ]]; then 
          # even element count, get the elements around the middle
          f1=${arr[ $(( (count - 1 ) /2 )) ]}
          f2=${arr[ $(( (count + 1 ) /2 )) ]}
          #echo "f1=$f1, f2=$f2"
          echo $(( ($f1 + f2) / 2 )) 
      else
          # odd element count
          echo ${arr[ $(( $count / 2 ))]}
      fi
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-06-27
        • 1970-01-01
        相关资源
        最近更新 更多