按相同出现次数对列进行排序 - 使用awk,sort,tr还是uniq?

时间:2013-02-08 00:53:15

标签: unix sorting awk tr uniq

假设我有一些以制表符分隔的数据:

Peter   5
Joe     8
Peter   7
Peter   8
Joe     4
Laura   3

我希望按照第一列中名称出现的次数(最大到最小)对其进行排序 所以我们有Peter(3次出现)Joe(2次出现)和Laura(1次出现)。

Peter   5
Peter   7
Peter   8
Joe     8
Joe     4
Laura   3

它只需要按第一列排序,而不是第二列排序。我一直在阅读sort的文档,我认为它没有这个功能。任何人都有一个简单的方法?

5 个答案:

答案 0 :(得分:3)

不性感但适合你的榜样:

 awk  'NR==FNR{a[$1]++;next}{ print a[$1],$0}' file file|sort -nr|sed -r 's/[0-9]* //'

使用您的数据进行测试:

kent$  cat n.txt
Peter   5
Joe     8
Peter   7
Peter   8
Joe     4
Laura   3

kent$  awk  'NR==FNR{a[$1]++;next}{ print a[$1],$0}' n.txt n.txt|sort -nr|sed -r 's/[0-9]* //'
Peter   8
Peter   7
Peter   5
Joe     8
Joe     4
Laura   3

答案 1 :(得分:1)

这有效:

for person in $(awk '{print $1}' file.txt | sort | uniq -c | sort -dnr | awk '{print $2}');
do grep -e "^$person[[:space:]]" file.txt;
done

答案 2 :(得分:0)

这是使用GNU awk的一种方式。像:

一样运行
awk -f script.awk file

script.awk的内容:

BEGIN {
    FS="\t"
}

{
    c[$1]++
    r[$1] = (r[$1] ? r[$1] ORS : "") $0
}

END {

    for (i in c) {
        a[c[i],i] = i
    }

    n = asorti(a)

    for (i=1;i<=n;i++) {
        split(a[i], b, SUBSEP)
        x[++j] = b[2]
    }

    for (i=n;i>=1;i--) {
        print r[x[i]]
    }
}

结果:

Peter   5
Peter   7
Peter   8
Joe     8
Joe     4
Laura   3

答案 3 :(得分:0)

这是一个令人惊讶的难以排序的标准。这段代码有效,但很难看:

data=${1:-data}
awk '{ print $1 }' $data |
sort |
uniq -c |
sort -k2 |
join -1 2 -2 2 -o 1.1,2.1,2.2,2.3 - <(awk '{ print NR, $0 }' $data | sort -k2) |
sort -k1,1nr -k3,3 -k2n |
awk 'BEGIN{OFS="\t"} { print $3, $4 }'

它假设bash 4.x代表'进程替换',但不使用内置于awk的任何排序(与POSIX awk相比,这是GNU扩展)。使用显式临时文件,可以使其在shell中工作而无需进程替换。

data=${1:-data}                  # File named on command line, or uses name 'data'
awk '{ print $1 }' $data |       # List of names
sort |                           # Sorted list of names
uniq -c |                        # Count occurrences of each name
sort -k2 |                       # Sort in name order
join -1 2 -2 2 -o 1.1,2.1,2.2,2.3 - <(awk '{ print NR, $0 }' $data | sort -k2) |
# The process substitution numbers each record in sequence and sorts in name order
# The join matches the names (column 2) and outputs the frequency, record number, name, value
sort -k1,1nr -k3,3 -k2n |        # Sort on frequency reversed, name, original line number
awk 'BEGIN{OFS="\t"} { print $3, $4 }'   # Print name and value

将GNU awk与内置排序或Perl或Python一起使用可能比这更好。

对于原始数据,输出为:

Peter   5
Peter   7
Peter   8
Joe     8
Joe     4
Laura   3

鉴于此数据的扩展版本:

Peter   5
Joe     8
Peter   7
Peter   8
Joe     4
Laura   3
Peter   50
Joe     80
Peter   70
Peter   80
Joe     40
Laura   30
Peter   700
Peter   800
Peter   7002
Peter   8002
Peter   7000
Peter   8000
Peter   7001
Peter   8001
Pater   50
Jae     80
Pater   70
Pater   80
Jae     40
Laura   30

输出结果为:

Peter   5
Peter   7
Peter   8
Peter   50
Peter   70
Peter   80
Peter   700
Peter   800
Peter   7002
Peter   8002
Peter   7000
Peter   8000
Peter   7001
Peter   8001
Joe     8
Joe     4
Joe     80
Joe     40
Laura   3
Laura   30
Laura   30
Pater   50
Pater   70
Pater   80
Jae     80
Jae     40

此数据集需要-k3,3排序术语;它在Pater的条目之前对Laura的条目进行排序(当省略时,你会将这两个列表交错)。

答案 4 :(得分:0)

这是使用awk的另一个:

  

awk'{a [$ 1,++ b [$ 1]] = $ 0; if(b [$ 1]&gt; max)max = b [$ 1]}

   END{ for(x=max;x>=1;x--)
         for( k in b )
           if( a[k,x] )
              for(y=1;y<=x;y++) {
                    print a[k,y]
                    delete a[k,y]
               }
   }' filename

使用gawk和POSIX awk可以正常工作。 END语句中存在三个循环可能会影响大文件的性能。