【问题标题】:How to count instances of string in a tab separated value file?如何计算制表符分隔值文件中的字符串实例?
【发布时间】:2012-05-14 22:26:03
【问题描述】:

如何计算制表符分隔值 (tsv) 文件中字符串的实例数?

tsv文件有几亿行,每一行的格式为

foobar1  1  xxx   yyy
foobar1  2  xxx   yyy
foobar2  2  xxx   yyy
foobar2  3  xxx   yyy
foobar1  3  xxx   zzz

。如何计算文件中整个第二列中每个唯一整数的实例,理想情况下将计数添加为每行中的第五个值?

foobar1  1  xxx   yyy  1
foobar1  2  xxx   yyy  2
foobar2  2  xxx   yyy  2 
foobar2  3  xxx   yyy  2
foobar1  3  xxx   zzz  2

我更喜欢只使用 UNIX 命令行流处理程序的解决方案。

【问题讨论】:

  • 请粘贴一些示例数据,以及您期望的输出。

标签: csv awk sed scripting


【解决方案1】:

我不完全清楚你想做什么。您是要根据第二列的值添加 0/1 作为第五列,还是要获取第二列中值的分布,整个文件的总计?

在第一种情况下,使用 awk -F'\t' '{ if($2 == valueToCheck) { c = 1 } else { c = 0 }; print $0 "\t" c }' < file 之类的东西。

在第二种情况下,使用 awk -F'\t' '{ h[$2] += 1 } END { for(val in h) print val ": " h[val] }' < file 之类的东西。

【讨论】:

  • 第二种情况是我认为需要的,但需要第二次通过文件才能将计数附加到每行的末尾。可以边做边做,但复杂性会增加,而且本质上仍然是两遍。
  • 使用数组h[$2]的适用性是否取决于最大整数有多大?无需检查,但第二列中的某些整数可能大于最大机器数。
【解决方案2】:

使用perl 的一个解决方案假设第二列的值已排序,我的意思是,当找到值2 时,具有相同值的所有行将是连续的。该脚本保留行,直到它在第二列中找到不同的值,获取计数,打印它们并释放内存,因此无论输入文件有多大都不会产生问题:

script.pl的内容:

use warnings;
use strict;

my (%lines, $count);

while ( <> ) { 

    ## Remove last '\n'.
    chomp;

    ## Split line in spaces.
    my @f = split;

    ## Assume as malformed line if it hasn't four fields and omit it.
    next unless @f == 4;

    ## Save lines in a hash until found a different value in second column.
    ## First line is special, because hash will always be empty.
    ## In last line avoid reading next one, otherwise I would lose lines
    ## saved in the hash.
    ## The hash will ony have one key at same time.
    if ( exists $lines{ $f[1] } or $. == 1 ) { 
        push @{ $lines{ $f[1] } }, $_; 
        ++$count;
        next if ! eof;
    }   

    ## At this point, the second field of the file has changed (or is last line), so 
    ## I will print previous lines saved in the hash, remove then and begin saving 
    ## lines with new value.

    ## The value of the second column will be the key of the hash, get it now.
    my ($key) = keys %lines;

    ## Read each line of the hash and print it appending the repeated lines as
    ## last field.
    while ( @{ $lines{ $key } } ) { 
        printf qq[%s\t%d\n], shift @{ $lines{ $key } }, $count;
    }   

    ## Clear hash.
    %lines = (); 

    ## Add current line to hash, initialize counter and repeat all process 
    ## until end of file.
    push @{ $lines{ $f[1] } }, $_; 
    $count = 1;
}

infile的内容:

foobar1  1  xxx   yyy
foobar1  2  xxx   yyy
foobar2  2  xxx   yyy
foobar2  3  xxx   yyy
foobar1  3  xxx   zzz

像这样运行它:

perl script.pl infile

输出如下:

foobar1  1  xxx   yyy   1
foobar1  2  xxx   yyy   2
foobar2  2  xxx   yyy   2
foobar2  3  xxx   yyy   2
foobar1  3  xxx   zzz   2

【讨论】:

    猜你喜欢
    • 2012-07-29
    • 1970-01-01
    • 2020-12-15
    • 1970-01-01
    • 1970-01-01
    • 2013-07-23
    • 2018-04-20
    • 2022-10-24
    • 2021-03-21
    相关资源
    最近更新 更多