Perl хэш массива, как проверить, существует ли объект перед добавлением - PullRequest
1 голос
/ 10 ноября 2019

У меня есть этот код, чтобы взять строки и поместить их в %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

Ответы [ 3 ]

3 голосов
/ 10 ноября 2019

Вы можете временно использовать 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 в любом месте строки!

2 голосов
/ 10 ноября 2019

Вы можете использовать grep () с блоком, который проверяет, равен ли app_id тому, который будет вставлен.

...
push @{$data{$ci_name}}, {app_id => $app_id, app_name => $app_name } unless grep { $_->{'app_id'} == $app_id; } @{$data{$ci_name}};
...
0 голосов
/ 10 ноября 2019

Если вы хотите сохранить все записи (адаптировано из @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}++;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...