Perl - 从arrayref中删除不需要的元素

时间:2010-03-05 10:35:34

标签: perl parsing

我正在编写一个解析“pure-ftpwho -s”命令的脚本,以获取当前传输的列表。但是当用户断开与FTP的连接并重新连接并恢复传输时,该文件会显示两次。我想用Perl删除鬼影。解析之后,这是arrayref的样子(使用Data :: Dumper转储)

$VAR1 = [
      {
        'status' => 'DL',
        'percent' => '20',
        'speed' => '10',
        'file' => 'somefile.txt',
        'user' => 'user1',
        'size' => '14648'
      },
      {
        'status' => 'DL',
        'percent' => '63',
        'speed' => '11',
        'file' => 'somefile.txt',
        'user' => 'user1',
        'size' => '14648'
      },
      {
        'status' => 'DL',
        'percent' => '16',
        'speed' => '60',
        'file' => 'somefile.txt',
        'user' => 'user2',
        'size' => '14648'
      }
    ];

这里user1和user2正在下载相同的文件,但是user1出现两次,因为第一个是“ghost”。检查和删除不需要的元素(在这种情况下是arrayref的第一个元素)的最佳方法是什么。要检查的条件是 - 如果“file”键和“user”键相同,则删除包含较小值“percent”键的hashref(如果它们相同则删除除1之外的所有键)。

6 个答案:

答案 0 :(得分:4)

如果原始arrayref中的顺序无关紧要,则应该有效:

my %users;
my @result;

for my $data (@$arrayref) {
    push @{ $users{$data->{user}.$data->{file}} }, $data;
}

for my $value (values %users) {
    my @data = sort { $a->{percent} <=> $b->{percent} } @$value;
    push @result, $data[-1];
}

这绝对可以提高效率。

答案 1 :(得分:4)

在这种情况下,正确的解决方案是在解析日志文件时使用哈希。将所有信息放入哈希值,例如%log,由userfile键入:

$log{$user}->{$file} = {
    'status' => 'DL',
    'percent' => '20',
    'speed' => '10',
    'size' => '14648'
};

等。日志文件中的后期条目将覆盖之前的条目。或者,您可以选择覆盖完成率较低的条目和完成率较高的条目。

使用散列可以解决许多完全多余的代码,这些代码可以解决错误数据结构的选择问题。

答案 2 :(得分:3)

对于它的价值,这是我的(略微)替代方法。同样,它不保留原始顺序:

my %most_progress;

for my $data ( sort { $b->{percent} <=> $a->{percent} } @$data ) {
    next if exists $most_progress{$data->{user}.$data->{file}};
    $most_progress{$data->{user}.$data->{file}} = $data;
}

my @clean_data = values %most_progress;

答案 3 :(得分:2)

这将保留顺序:

use strict;
use warnings;

my $data = [ ... ]; # As posted.

my %pct;
for my $i ( 0 .. $#{$data} ){
    my $r = $data->[$i];
    my $k = join '|', $r->{file}, $r->{user};
    next if exists $pct{$k} and $pct{$k}[1] >= $r->{percent};
    $pct{$k} = [$i, $r->{percent}];
}

@$data = @$data[sort map $_->[0], values %pct];

答案 4 :(得分:0)

my %check; 

for (my $i = 0; $i <= $#{$arrayref}; $i++) { 
  my $transfer = $arrayref->[$i]; 

  # check the transfer for user and file 
  my $key = $transfer->{user} . $transfer->{file};  
  $check{$key} = { } if ( !exists $check{$key} ); 

  if ( $transfer->{percent} <= $check{$key}->{percent} ) { 
    # undefine this less advanced transfer 
    $arrayref->[$i] = undef; 

  } else { 
    # remove the other transfer 
    $arrayref->[$check{$key}->{index}] = undef if exists $check{$key}->{index}; 

    # set the new standard 
    $check{$key} = { index => $i, percent => $transfer->{percent} } 
  } 
}  

# remove all undefined transfers     
$arrayref = [ grep { defined $_ } @$arrayref ];

答案 5 :(得分:0)

使用Perl6::Gather

对主题进行更改
use Perl6::Gather;

my @cleaned = gather {
    my %seen;
    for (sort { $b->{percent} <=> $a->{percent} } @$data) {
        take unless $seen{ $_->{user} . $_->{file} }++;
    }
};