【问题标题】:Sum counts in a text file文本文件中的总和计数
【发布时间】:2015-09-08 13:16:52
【问题描述】:

我经常会通过gnu parallel 得到一个包含各种对象计数的大文件:

1201 object1
804 object1
327 object2
3828 object1
29 object2
277 object3
...

这通常会有数千行,其中包含不分特定顺序的各种对象。我想要每个对象的总计数的总和。我通常的做法是像这样组合一个 Perl 单行代码:

perl -lane '$O{$F[1]} += $F[0]; END {foreach $k (keys %O) {print "$k: $O{$k}"}}' countsfile

我通常会有一个由 parallel、awk、grep、sort、uniq、cut 等组成的管道,每个管道都有相当简洁的参数。 perl hack 是一个例外:它的输入时间很长,并且比管道的其他部分复杂得多。我总是觉得我在输入时指定的内容远远超出了我真正需要的内容。

所以我的问题是:有没有一种技术或实用程序可以让我做到这一点,而无需每次都编写完整的脚本?我希望能够在不使用 perl、awk、R 或其他实现通用语言的系统的情况下做到这一点。

【问题讨论】:

  • 为什么不将脚本存储在一个文件中并简单地执行脚本?
  • 我相信这里的标准解决方案是 awk 或 perl 单行。我,我很久以前就厌倦了,写了一个“数学编辑器”工具,让我可以轻松调用像 med 'sum(c1)' 这样的东西,它只是对第 1 列求和,但由于这不是标准实用程序,它不是你的问题。
  • “标准”不是什么大不了的事——你有没有在任何地方发表过?
  • 它在 eskimo.com/~scs/src/#med ,但恐怕它仍然对你没有帮助,因为我误读了你提出的问题,这最终比 med 可以处理的更复杂。跨度>

标签: perl unix command-line awk


【解决方案1】:

您的大部分代码都在END 块中以显示哈希值。您可以使用while 而不是for 使之更简洁

perl -lanE '$O{$F[1]} += $F[0]; END {say "@v" while @v = each %O}}' countsfile

输出

object1 5833
object3 277
object2 356

或者,如果您倾向于安装 Data::Dump,您可能会完全失去循环

perl -MData::Dump -lanE '$O{$F[1]} += $F[0]; END {dd \%O}' countsfile

输出

{ object1 => 5833, object2 => 356, object3 => 277 }

您甚至可以弄乱语法以避免需要 END

perl -lanE '$O{$F[1]} += $F[0];}{say "@v" while @v = each %O' countsfile

【讨论】:

  • 我希望避免这种结构,并且正在寻找比 perl 更专业的工具。
  • @DougLuce:那么恐怕你的问题还不清楚。有人问您为什么不简单地将 Perl 代码放入程序文件中。您没有对此做出回应,我无法想象更专业的工具。同时你说你“打算保留管道建设”,这似乎是相反的方向。您拥有的唯一其他答案与我自己的答案非常相似,但使用 awk 代替 Perl,所以不仅仅是我愚蠢
  • @DougLuce 为什么有人会为此创建一个实用程序,而它只需不到一行代码就可以轻松实现?
  • 查看 Steve Summit 对我的问题的评论。我厌倦了为这种情况编写非常相似的单行脚本。我的问题不是“我应该把我的脚本放到一个文件中并在不同的地方运行它吗”,也不是这个效果的答案和 cmets 特别有用。
  • while in the end 子句作为成语很好,谢谢。我只是在另一个我想象的实用程序应该解决的情况下使用它:perl -alne '$x{$F[0]} .= $F[1] . " "; END {print "@v" while @v = each %x}'
【解决方案2】:

awk:

awk '{sum[$2]+=$1}END{for(i in sum)print i,sum[i]}' File

以第二个单词(objectx)为索引,更新sum数组。也就是将第一个字段 (number) 加到 sum[objectx]。最后,打印每个索引和该索引处的元素(这将是总和)。

示例:

AMD$ awk '{sum[$2]+=$1}END{for(i in sum)print i,sum[i]}' File
object1 5833
object2 356
object3 277

【讨论】:

  • 这真的不是我已经在做的改进。我想避免编写 perl 或 awk 或任何需要这种复杂程度的东西。所以我正在寻找专门的东西。
  • 也许你可以定义一个别名并使用它... alias mycmd="awk '{sum[\$2]+=\$1}END{for(i in sum)print i,sum[一世]}'” 。你也可以把它添加到你的 .bashrc 中。然后像 mycmd 文件一样使用它......对不起,我不知道任何其他更简单的实用程序这样......
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-02-09
  • 1970-01-01
  • 2012-10-27
  • 2015-10-05
  • 2017-12-25
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多