数组中最常见的元素(bash 3.2)

时间:2017-04-16 18:10:27

标签: arrays bash macos shell

在使用bash的shell脚本中,我希望找到数组中最常出现的数字,并将结果存储在变量$ result中。该数组可以包含任意数量的值。如果返回多个结果,那么我想选择最小的数字。

我理解bash可能不是最好的工具,我愿意在Mac OS X系统上使用我脚本中命令行提供的工具提供建议。

示例:

array =(03 03 03 04 04 04 04)
03次发生3次 4次发生04次 应该将04返回到名为$ result的变量。

另一个例子:

array =(03 03 03 03 04 04 04 04 04)
03次发生4次 4次发生04次 选择最小数字,即03
应该将03返回到名为$ result的变量中。

谢谢你的帮助。

3 个答案:

答案 0 :(得分:3)

你的问题中存在一个需要解决的含糊之处:你说数组是一个数字的数组,但是这个例子给它们带来了前导零,如果你这会带来一些惊喜将字符串视为数字(它们将以八进制解释)。

除此之外,解决方案相对简单:使用sortuniq计算每个值的实例数,按计数对结果进行排序,然后提取第一个值。为了满足sort的要求,我们首先使用printf

在每行写一个元素
printf '%s\n' "${arr[@]}" | sort | uniq -c |
sort -k1,1nr -k2 | awk '{print $2; exit}'

sort的两次调用都将原始数据排序为字符串。如果你真的想将它们分类为数字,你可以使用:

printf '%d\n' "${arr[@]}" | sort -n | uniq -c |
sort -k1,1nr -k2n | awk '{print $2; exit}'

虽然这会将所有数字规范化为规范形式(以便03成为3)。

答案 1 :(得分:2)

这是一个基于awk的解决方案,可以避免使用bash关联数组:

#!/bin/bash
get_result(){
awk '
  { 
      n=++hsh[$1]
      if(n>max_occ){
         max_occ=n
         what=$1
      }else if(n==max_occ){
         if(what>$1) 
             what=$1
      }
  } 
  END { print what }
'
}

array=(03 03 03 04 04 04 04)
result=$(printf "%s\n" "${array[@]}" |  get_result)
echo $result

array=(03 03 03 03 04 04 04 04)
result=$(printf "%s\n" "${array[@]}" |  get_result)
echo $result

结果为03和04,如您的示例所示。

答案 2 :(得分:0)

您可以使用关联数组来跟踪数组元素的频率:

#!/bin/bash

arr=(1 2 3 4 4 44 4 4 5 5)
declare -A hash
max_times=0
for i in "${arr[@]}"; do
  ((hash[$i]++))
  h=${hash[$i]}
  if [[ $h > $max_times ]]; then
    max=$i
    max_times=$h
  fi
done

echo max=$max, max_times=$max_times

输出:

max=4, max_times=4

如果我们不能使用关联数组,那么我们可以使用外部工具:

array=(1 3 3 333 5 66 5 33 66 66 33 22 11)
printf '%d\n' "${array[@]}" | sort -n | uniq -c | sort -n | tail -1

输出:

  3 66