列表数组查找double并添加值

时间:2014-06-14 09:24:47

标签: perl

原始的perl数组已经排序,如下所示:

Original ARRARY:
ccc-->2
ccc-->5
abc-->3
abc-->7
cb-->6

我希望得到以下结果:

FINAL ARRARY:
ccc-->7
abc-->10
cb-->6

问题:
你可以为此创建一个子程序吗?

这是原创。我使用的子程序:

sub read_final_dev_file {

 $dfcnt=0;
 $DEVICE_ANZSUMZW=0;
 $DEVICE_ANZSUM=0;

 open(DATA,"$log_dir1/ALLDEVSORT.$log_file_ext1") || die ("Cannot Open Logfile: $log_dir1/$log_DEV_name.$log_file_ext1 !!!!");
 @lines = <DATA>;
 close(DATA);
 chomp(@lines); # erase the last sign from a string

  foreach $logline (@lines) {


         if ($logline =~ /(.*)-->(.*)/) {
            $DEVICE_CODE[$dfcnt] = $1;
            $DEVICE_ANZAHL[$dfcnt] = $2;



            print "DEVICE_final = $DEVICE_CODE[$dfcnt], D_ANZAHL_final = $DEVICE_ANZAHL[$dfcnt]\n";

            if ($dfcnt > 0 ) {


             if ( $DEVICE_CODE[$dfcnt] eq $DEVICE_CODE[$dfcnt-1] ) {
                     $DEVICE_ANZSUM = $DEVICE_ANZAHL[$dfcnt] + $DEVICE_ANZAHL[$dfcnt-1];
                     $DEVICE_ANZSUMZW = $DEVICE_ANZSUM++;
                     #$DEVICE_ANZSUM = $DEVICE_ANZAHL[$dfcnt]++;
                     #print "DEVICE_ANZAHL = $DEVICE_ANZAHL[$dfcnt],DEVICE_ANZAHL -1 = $DEVICE_ANZAHL[$dfcnt-1]\n";
                     print "DEVICE_eq = $DEVICE_CODE[$dfcnt], D_ANZAHL_eq = $DEVICE_ANZAHL[$dfcnt],DEVANZSUM = $DEVICE_ANZSUM,COUNT = $dfcnt\n";

                      }#end if

                if ( $DEVICE_CODE[$dfcnt] ne $DEVICE_CODE[$dfcnt-1] ) {
                     #$DEVICE_ANZSUM=0;
                   #splice(@data3,$dfcnt+2,1) if ($DEVICE_ANZSUM > 1);
                   push (@data3,$DEVICE_ANZSUMZW) if ($DEVICE_ANZSUM > 1);
                   push (@data3,$DEVICE_ANZAHL[$dfcnt]) if ($DEVICE_ANZSUM == 0);
                   if ( $DEVICE_CODE[$dfcnt] ne $DEVICE_CODE[$dfcnt-1] ) {
                   $DEVICE_ANZSUM=0;
                     }

                   print "DEVICE_ne = $DEVICE_CODE[$dfcnt], D_ANZAHL_ne = $DEVICE_ANZAHL[$dfcnt], DEVANZSUM = $DEVICE_ANZSUM\n";


                    }#end if
                 }#end if $dfcnt

           $dfcnt++;
        }#end if logline

    }#end for



print "@labels3\n";
print "@data3\n";




}#end sub read_final_dev_file

3 个答案:

答案 0 :(得分:2)

可能不是最好的方式,但这是看到LeoNerd回答之后想到的,因为我没有生产中的CPAN访问权限,并且从来没有模块存在:

#!/usr/bin/perl
use strict;
use warnings;
use Data::Dumper;

my @input = (
  [ ccc => 2 ],
  [ ccc => 5 ],
  [ abc => 3 ],
  [ abc => 7 ],
  [ cb  => 6 ],
);

my %output;
$output{$_->[0]} += $_->[1] for @input;
print Dumper \%output;

my @output = map { [ $_ => $output{$_} ] } keys(%output);
print Dumper \@output;

输出:

$VAR1 = {
          'abc' => 10,
          'cb' => 6,
          'ccc' => 7
        };
$VAR1 = [
          ['abc', 10],
          ['cb', 6],
          ['ccc', 7],
        ];

答案 1 :(得分:0)

您可以使用List::UtilsBy::partition_by通过第一个字符串将原始列表分组到分区中:

use List::UtilsBy qw( partition_by );

my @input = (
  [ ccc => 2 ],
  [ ccc => 5 ],
  [ abc => 3 ],
  [ abc => 7 ],
  [ cb  => 6 ],
);

my %sets = partition_by { $_->[0] } @input;

现在你有一个哈希,由前导字符串键入,其值是所有ARRAY引用首先使用该键。您现在可以通过映射包含数字的$_->[1]来对它们中的值求和:

use List::Util qw( sum );

my %totals;
foreach my $key ( keys %sets ) {
  $totals{$key} = sum map { $_->[1] } @{ $sets{$key} };
}

如果您倾向于使用更紧凑和功能性更强的代码,那么您可以在此处使用新的pairmap;使整个事物在一行中表达出来:

use List::UtilsBy qw( partition_by );
use List::Util qw( pairmap sum );

my %totals = pairmap { $a => sum map { $_->[1] } @$b }
             partition_by { $_->[0] } @input;

编辑:我应该补充一点,即使您在原始问题中声明数组已排序,但此解决方案并不需要对其进行排序。它会愉快地以任何顺序接受输入。

答案 2 :(得分:0)

通过使用哈希来跟踪计数而不是数组,可以大大简化子例程。以下使用数组@devices来跟踪订单,使用哈希%device_counts来跟踪计数:

my @devices;
my %device_counts;

while (<DATA>) { # Read one line at a time from DATA
    if (/(.*)-->(.*)/) { # This won't extract newlines so no need to chomp
        if (!exists $device_counts{$1}) {
            push @devices, $1; # Add to the array the first time we encounter a device
        }
        $device_counts{$1} += $2; # Add to the count for this device
    }
}

for my $device (@devices) {
    printf "%s-->%s\n", $device, $device_counts{$device};
}