【问题标题】:generating frequency table from file从文件生成频率表
【发布时间】:2011-08-28 00:32:37
【问题描述】:

给定一个每行包含一个数字的输入文件,我如何计算一个项目在该文件中出现的次数?

cat input.txt
1
2
1
3
1
0

期望的输出(=>[1,3,1,1]):

cat output.txt
0 1
1 3
2 1
3 1

如果解决方案也可以扩展到浮点数,那就太好了。

【问题讨论】:

标签: bash file shell awk


【解决方案1】:

你的意思是你想计算一个项目在输入文件中出现的次数?首先对其进行排序(使用-n,如果输入始终是数字,如您的示例所示)然后计算唯一结果。

sort -n input.txt | uniq -c

【讨论】:

  • 我不知道uniq 命令。我把它改成了cat input.txt | sort -n | uniq -c | awk '{print $2 " " $1}',现在我得到了想要的输出。
  • 您可以使用 awk 来获取订单,但您不需要在此处使用 cat。您应该了解< 运算符,以将文件输入到程序中,甚至是循环构造之类的东西。有关幽默值,请参阅the useless use of cat awards
【解决方案2】:

另一种选择:

awk '{n[$1]++} END {for (i in n) print i,n[i]}' input.txt | sort -n > output.txt

【讨论】:

  • @Javier,'n' 数组只是保留它在输入文件中看到的字符串的计数。它可以是 int、float 或任意字符串。是的,'END' 部分在输入文件被完全读取后执行。您不需要在 awk 中初始化变量:未初始化的变量被视为零或空字符串(取决于上下文)。在这种情况下,'i' 是一个循环变量。我认为默认的“排序”行为是考虑整行。此解决方案适用于输入文件中的任何内容:awk 数组是关联数组。
  • 感谢您提供awk-based 解决方案。据我了解,在第一部分中,考虑$1 列中的元素,您将histogram 存储到n 数组中。 END 部分意味着它将完成after 直方图已构建,对吗? awk中的循环是否不需要初始化变量i?然后,sort -n 将仅应用于输出的第一列:i, n[i],对吗?即不在n[i]?此外,此解决方案仅适用于 integer 数字(因为数组的索引)?
  • awk 解决方案的明显优势在于不需要sort!要获得排序的输出,只需跟踪看到的最大值和最小值并遍历它们,检查每个值是否在数组中。 (但这仅适用于整数,不适用于浮点数。)
  • 也适用于字符串!只需将第一个单词$1 更改为$0,整行:awk '{n[$0]++} END {for (i in n) print i,n[i]}' 让您轻松查找和计算输入中的重复行。太棒了。
  • 我刚刚删除了一条评论,其中我说我遇到了基于 awk 的解决方案的错误。实际上,这是我的代码中的一个错误。由于其他人也可能这样做,我认为在这里分享我的经验可能会很有用:我的问题是,可能受 for 循环的 shell 语法的影响,我添加了一个“;”在awk 命令的“END”部分中的“for”和“print”之间。结果,for 循环什么也没做,打印操作只使用了i 的最后一个值。
【解决方案3】:

使用 Debian 中的maphimbu stda 包:

# use 'jot' to generate 100 random numbers between 1 and 5
# and 'maphimbu' to print sorted "histogram":
jot -r 100 1 5 | maphimbu -s 1

输出:

             1                20
             2                21
             3                20
             4                21
             5                18

maphimbu 也适用于浮点数:

jot -r 100.0 10 15 | numprocess /%10/ | maphimbu -s 1

输出:

             1                21
           1.1                17
           1.2                14
           1.3                18
           1.4                11
           1.5                19

【讨论】:

    【解决方案4】:

    至少其中一些可以做到

    sort output.txt | uniq -c
    

    但是number count 的顺序是相反的。这将解决这个问题。

    sort test.dat | uniq -c | awk '{print $2, $1}'
    

    【讨论】:

    • 如果第一列中的项目长度不同,这会使对齐有点混乱,因此您可以在重新排列列时使用制表符而不是默认空间:sort test.dat | uniq -c | awk '{print $2"\t"$1}'
    【解决方案5】:

    除了其他答案,你可以use awk to make a simple graph。 (但是,同样,它不是直方图。)

    【讨论】:

      【解决方案6】:
      perl -lne '$h{$_}++; END{for $n (sort keys %h) {print "$n\t$h{$n}"}}' input.txt
      

      -n循环遍历每一行
      每个$_ 数字递增哈希%h
      一旦达到input.txtEND
      sort {$a <=> $b} 的哈希值
      打印号码$n和频率$h{$n}

      适用于浮点的类似代码:

      perl -lne '$h{int($_)}++; END{for $n (sort {$a <=> $b} keys %h) {print "$n\t$h{$n}"}}' float.txt
      

      float.txt

      1.732
      2.236
      1.442
      3.162
      1.260
      0.707
      

      输出:

      0       1
      1       3
      2       1
      3       1
      

      【讨论】:

      • sort keys %h 使用字典排序;它没有按数字排序。
      【解决方案7】:

      我遇到了与描述类似的问题,但涉及千兆字节的 gzip 日志文件。因为其中许多解决方案需要等到所有数据都被解析完毕,所以我选择编写 rare 来基于正则表达式快速解析和聚合数据。

      在上面的例子中,就像将数据传递给直方图函数一样简单:

      rare histo input.txt
      # OR
      cat input.txt | rare histo
      
      # Outputs:
      1                   3         
      0                   1         
      2                   1         
      3                   1
      

      但它也可以通过正则表达式/表达式处理更复杂的情况,例如:

      rare histo --match "(\d+)" --extract "{1}" input.txt
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-09-26
        • 2020-03-21
        • 2023-03-12
        • 2016-04-23
        • 1970-01-01
        • 2019-05-20
        相关资源
        最近更新 更多