awk:我如何计算跨列的字符串出现次数并找到跨行的最大值?

时间:2016-01-19 00:42:13

标签: linux bash awk

我的Linux上的bash脚本有问题。

我的输入如下:

  input
    Karydhs     y n y y y n n y n n n y n y n 

    Markopoulos y y n n n y n y n y y n n n y

    name3       y n y n n n n n y y n y n y n

等...

其中y =是,n =否,这是投票的结果......现在我希望使用awk来显示每个人(姓名)和该人的姓名和总投票数那个胜利(获得最多y),任何想法?

我这样做:

awk '{count=0 for (I=1;i<=15;i++) if (a[I]="y") count++} {print $1,count}' filename

5 个答案:

答案 0 :(得分:1)

这个怎么样?

awk '{ for (i=2;i<NF;i++) { if ($i=="y") { a[$1" "$i]++} } } END { print "Yes tally"; l=0; for (i in a) { print i,a[i]; if (l>a[i]) { l=l } else { l=a[i];name=i }   } split(name,a," "); print "Winner is ",a[1],"with ",l,"votes"  } ' f
Yes tally
name3 y 6
Markopoulos y 6
Karydhs y 7
Winner is  Karydhs with  7 votes

答案 1 :(得分:1)

替代双通awk

$ awk '{print $1; $1=""}1' votes | 
  awk -Fy 'NR%2{printf "%s ",$0; next} {print NF-1}' | 
  sort -k2nr

Karydhs 7
Markopoulos 7
name3 6

答案 2 :(得分:1)

这是一个快速(不需要排序,没有明确的&#34; for&#34;循环),一次性解决方案,考虑到关系的可能性:

awk 'NF==0{next} 
  {name=$1; $1=""; gsub(/[^y]/,"",$0); l=length($0); 
   print name, l;
   if (mx=="" || mx < l) { mx=l; tie=""; winner=name; }
   else if (mx == l) {
          tie = 1; winner = winner", "name;
        }
  }
  END {fmt = tie ? "The winners have won %d votes each:\n" :
                   "The winner has won %d votes:\n";
       printf fmt, mx;
       print winner;
  }'

输出:

Karydhs 7
Markopoulos 7
name3 6
The winners have won 7 votes each:
Karydhs, Markopoulos

注意:上面的程序是为了便于阅读,但接受GNU awk显示的换行符。某些awks不允许拆分三元条件。

答案 3 :(得分:1)

这是另一种方法。

{ name=$1; $1=""; votes[name]=length(gensub("[^y]","","g")); }
END {asorti(votes,rank); for (r in rank) print rank[r], votes[rank[r]]; }

它类似于@ mklement0的答案,但它使用asorti()¹对awk内部进行排序。

  • name=$1保存令牌1的名称
  • $1="";清除令牌1,其副作用是将其从$ 0中移除
  • votes[name]是一个由候选人姓名
  • 索引的数组
  • gensub("[^y]","","g")删除了除了$ 0左边的所有内容之外的一切
  • length()统计他们
  • asorti(votes,rank)按指数对投票进行排序;此时数组看起来像这样:
    votes                 rank
    [name3] = 6           [1] = Karydhs
    [Markopoulos] = 7     [2] = Markopoulos
    [Karydhs] = 7         [3] = name3
    
  • for (r in rank) print rank[r], votes[rank[r]];打印结果:
    Karydhs 7
    Markopoulos 7
    name3 6
    

¹asorti()函数可能在某些版本的awk中不可用

答案 4 :(得分:0)

更简单且符合POSIX的awk解决方案,由sort协助:

awk '{
 printf "%s", $1
 $1=""
 yesCount=gsub("y", "")
 printf " %s\n", yesCount
 }' file | 
  sort -t ' ' -k2,2nr
  • printf "%s", $1仅打印名称字段,不带尾随换行符。
  • $1=""清除第一个字段,导致重建输入行$0,使其仅包含投票列。
  • yesCount=gsub("y", "")执行虚拟替换,利用Awk的gsub()函数返回已执行替换的 count 这一事实;实际上,返回值是该行上y值的数量。
  • printf " %s\n", yesCount然后打印yes票数作为第二个输出字段并终止该行。
  • sort -t ' ' -k2,2,nr然后按第二个(-k2,2)空格分隔的(-t ' ')字段对结果行进行排序,以数字方式(n),以相反的顺序排序{{1}因此,最高的是 - 投票计数首先出现。