0

我有一个名为listofvalues.txt. 该文件有 1000 多行和 5 列。

1,232,3434,54343,434343  
1,232,100,4546,3456  
1,122,45454,4546,3456  
2,212,334,5555,4654  
...  
...  

如果第 1 列和第 2 列相等,我想将第三列的值相加,并将结果打印到如下文件中

1,232,3534,54343,434343  
1,122,45454,4546,3456  
2,212,334,5555,4654  
....  
.........  
.........  
......  

你觉得我怎么能在 Perl 中做到这一点?由于我是 Perl 的新手,我发现它很难做到。

4

4 回答 4

3

该程序通过维护一个数组来工作,该数组@data包含具有唯一性的所有记录的列表column1|column2键的所有记录的列表。第一次在文件中遇到新键时,将完整的记录压入堆栈。每次后续遭遇只是将记录的第三个字段添加到原始值。

哈希%data维护对@data对应于每个不同键值的元素的引用。

use strict;
use warnings;

open my $fh, '<', 'listofvalues.txt' or die $!;

my @data;
my %data;

while (<$fh>) {
  chomp;
  my @record = split /,/;
  my $key = join '|', @record[0,1];
  if ($data{$key}) {
    $data{$key}[2] += $record[2];
  }
  else {
    push @data, ($data{$key} = \@record);
  }
}

print join(',', @$_), "\n" for @data;

输出

1,232,3534,54343,434343  
1,122,45454,4546,3456  
2,212,334,5555,4654

更新

单线解决方案

perl -F, -ane '$k="@F[0,1]";$s{$k}?$s{$k}[2]+=$F[2]:do{push@d,$k;$s{$k}=[@F]};END{$\"=',';print"@{$s{$_}}"for@d}' listofvalues.txt
于 2012-07-15T16:16:30.560 回答
1

这是另一个单线:

  perl -F, -lane '
  BEGIN { $, = "," }

  if(defined(@A)) {
    if($A[0] == $F[0] and $A[1] == $F[1]) {
      $A[3] +=  $F[3];
    } else {
      print @A;
      @A = (@F);
    }
  } else {
    @A = (@F);
  }

  END { print @A }' listofvalues.txt

请参阅perlrun(1)开关的含义。

于 2012-07-15T17:11:14.947 回答
0

仅仅因为你可以在单行中做到这一点并不意味着你应该;)

$ perl -F',' -lane '
push @order, [ @F[0,1] ]
  unless $seen{$F[0]}{$F[1]}++; # Preserve order
$total{$F[0]}{$F[1]} += $F[2];  # Sum up
$value{$F[0]}{$F[1]} = join ',' => @F[0,1], $total{$F[0]}{$F[1]}, @F[3..$#F];
} END {
    print $value{$_->{0]}{$_->[1]} for @order;
' file.txt
于 2012-07-15T16:23:48.400 回答
0

您可以尝试使用数据库方法,尽管它不处理 col4 或 col5。

#!/usr/bin/perl
use strict;
use warnings;
use DBI;

my $dbh = DBI->connect("DBI:CSV:");
$dbh->{'csv_tables'}->{'data'} = { 'file' => 'o33.txt',
    'col_names' => [qw/col1 col2 col3 col4 col5/]};

my $sql = <<SQL;
select col1, col2, SUM(col3)
from data
group by col1, col2
order by col1, col2
SQL

my $sth = $dbh->prepare( $sql );
$sth->execute;

{
    local $" = ',';
    while ( my $row = $sth->fetchrow_arrayref ) {
        print "@$row\n";
    }
}

__END__
C:\Old_Data\perlp>type o33.txt
1,232,3434,54343,434343
1,232,100,4546,3456
1,122,45454,4546,3456
2,212,334,5555,4654

C:\Old_Data\perlp>perl t3.pl
1,122,45454
1,232,3534
2,212,334
于 2012-07-15T20:29:11.017 回答