数组的Perl哈希如何在添加之前检查对象是否存在

问题描述 投票:0回答:3

我有这段代码可以将行放入%data。 DATA中的一行(最后一行)是重复的,因此我不希望将其添加到%data。在将该行推入app_id之前,如何检查ci_name%data组合尚不存在?有点像

push .. unless {app_id already exists}

要修改的代码:

#!/usr/bin/perl

use strict;
use warnings;
use Data::Dumper;

my %data;

while( <DATA> ) {
    chomp;
    next if /app_id/;
    my ($app_id,$ci_name,$app_name) = split /,/;
    push @{$data{$ci_name}}, {app_id => $app_id, app_name => $app_name };
}

print Dumper(\%data);

__DATA__
app_id,ci_name,app_name
1234,hosta7,Managed File Transfer
1235,hosta7,Patrtol
1236,hosta7,RELATIONAL DATA WAREHOUSE
1237,hosta7,Managed File Transfer
1238,hosta7,Initio Application
1239,hosta7,Data Warehouse Operations Infrastructure
2345,hostb,Tableou
2345,hostb,Tableou
perl hash
3个回答
2
投票

您可以将grep()与一个块一起使用,该块检查app_id是否等于要插入的块。

...
push @{$data{$ci_name}}, {app_id => $app_id, app_name => $app_name } unless grep { $_->{'app_id'} == $app_id; } @{$data{$ci_name}};
...

2
投票

您可以暂时使用HoH代替HoA。

#!/usr/bin/perl

use strict;
use warnings;
use Data::Dumper;

<DATA>;  # Skip header.

my %data;
my %seen;
while (<DATA>) {
    chomp;
    my ($app_id, $ci_name, $app_name) = split /,/;
    $data{$ci_name}{$app_id} //= { app_id => $app_id, app_name => $app_name };
}

# Convert HoH to HoA.
$data{$_} = [ values(%{ $data{$_} }) ]
   for keys(%data);

print Dumper(\%data);

以上内容保留第一个重复项,并且不保留顺序。将//=更改为=以保留最后的重复项。请继续阅读以获取保留订单的解决方案。


以下是在保留订单的同时删除重复项的常用方法:

my %seen;
my @uniq = grep !$seen{$_}++, @values;

我们可以根据需要调整习惯用法。

#!/usr/bin/perl

use strict;
use warnings;
use Data::Dumper;

<DATA>;  # Skip header.

my %data;
my %seen;
while (<DATA>) {
    chomp;
    my ($app_id, $ci_name, $app_name) = split /,/;
    push @{ $data{$ci_name} }, { app_id => $app_id, app_name => $app_name }
       if !$seen{$ci_name}{$app_id}++;
}

print Dumper(\%data);

上面保留了重复项的第一个,并保留了顺序。


这两个解决方案的速度均为O(N),而先前发布的解决方案的速度为O(N 2),因此此解决方案的伸缩性更好。不过,老实说,除非重复很多,否则以前发布的解决方案的实际速度为O(N)。


注意在循环之前如何添加<DATA>?这比跳过行中任何地方包含app_id的所有行要好得多!


0
投票

如果要保留所有记录(从@ikegami改编而来:]

#!/usr/bin/perl

use strict;
use warnings;
use Data::Dumper;

<DATA>;  # Skip header.

my %data;

while (<DATA>) {
    chomp;
    my ($app_id, $ci_name, $app_name) = split /,/;
    push @{ $data{$ci_name}{$app_id} }, { app_id => $app_id, app_name => $app_name };
}

print Dumper(\%data);

但是最好编写代码:

$data{$ci_name}{$app_id}{$app_name}++;
© www.soinside.com 2019 - 2024. All rights reserved.