簡體   English   中英

Awk:如何計算跨列字符串的出現次數並找到跨行的最大值?

[英]Awk: How do I count occurrences of a string across columns and find the maximum across rows?

我在 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=yes 和 n=no,這是投票的結果......現在我想使用awk來顯示每個人(姓名)和獲勝者(獲得最多 y ), 有任何想法嗎?

我做這樣的事情:

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

這是一個快速(不需要排序,沒有明確的“for”循環),考慮到關系可能性的一次性解決方案:

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 顯示的換行符。 某些 awk 不允許拆分三元條件。

那這個呢?

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

替代的兩遍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

這是另一種方法。

{ 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 的剩余部分刪除除 'y 之外的所有內容
  • 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 中可能不可用

一個更簡單且符合 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()函數返回執行的替換計數 實際上,返回值是行上y值的數量。
  • printf " %s\\n", yesCount然后打印 yes 票數作為第二個輸出字段並終止該行。
  • sort -t ' ' -k2,2,nr然后按第二個 ( -k2,2 ) 空格分隔 ( -t ' ' ) 字段按數字 ( n)以相反的順序 ( r ) 對結果行進行排序,以便最高的贊成票首先出現。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM