1

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

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

我想按名称在第一列中出现的次数(最大到最小)对其进行排序,所以我们有彼得(3 次出现)乔(2 次出现)和劳拉(1 次出现)。

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

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

4

5 回答 5

4

不性感,但适用于您的示例:

 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
于 2013-02-08T01:06:46.303 回答
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
于 2013-02-08T01:22:39.830 回答
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
于 2013-02-08T03:06:33.747 回答
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 }'

它假定bash4.x 用于“进程替换”,但不使用内置的任何排序awk(与 POSIX 相比,这是 GNU 扩展awk)。使用显式临时文件,它可以在没有进程替换的情况下在 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

awk使用带有内置排序的GNU ,或者 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 的条目进行排序(如果省略,则这两个列表交错排列)。

于 2013-02-08T05:06:05.900 回答
0

这是另一个使用 awk 的:

awk '{ a[ $1, ++b[$1] ]=$0 ; 如果(b[$1]>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 语句中存在三个循环可能会影响大文件的性能。

于 2013-02-08T05:15:54.353 回答