Удалить дубликаты ха sh из массива perl - PullRequest
1 голос
/ 17 января 2020

У меня есть массив perl, как показано ниже

my @arr = ({
  CONTEXTID => 1230,
  NAME => 'test8824',
  PROVIDERID => 163
}, {
  CONTEXTID => 8824,
  NAME => 'test8824',
  PROVIDERID => 77
}, {
  CONTEXTID => 8824,
  NAME => 'test8824',
  PROVIDERID => 779
}, {
  CONTEXTID => 8824,
  NAME => 'test8824',
  PROVIDERID => 141
}, {
  CONTEXTID => 1230,
  NAME => 'test8824',
  PROVIDERID => 163
})

Я хочу удалить дублирующиеся хэши из массива. Вывод должен выглядеть следующим образом:

({
  CONTEXTID => 1230,
  NAME => 'test8824',
  PROVIDERID => 163
}, {
  CONTEXTID => 8824,
  NAME => 'test8824',
  PROVIDERID => 77
}, {
  CONTEXTID => 8824,
  NAME => 'test8824',
  PROVIDERID => 779
}, {
  CONTEXTID => 8824,
  NAME => 'test8824',
  PROVIDERID => 141
}
)

Дубликат будет идентифицирован только тогда, когда все ключи га sh совпадают, иначе он не дублируется.

Ответы [ 3 ]

4 голосов
/ 17 января 2020

Ниже приводится распространенная идиома для удаления дубликатов:

my %seen;    
my @unique = grep !$seen{$_}++, @strings;

, которые используют сравнения строк, чтобы определить, идентичны ли два элемента или нет. Это не сработает в нашем случае (так как это позволит эффективно сравнить адреса хэшей, находя их все уникальными).

Но мы можем легко обобщить приведенное выше:

my %seen;    
my @unique = grep !$seen{key($_)}++, @items;

Все, что нам сейчас нужно, - это функция key, которая создает строку таким образом, чтобы выполнялись следующие условия:

  • key($a) ne key($b), если $a считается отличным от $b.
  • key($a) eq key($b), если $a считается таким же, как $b.

В этом случае мы можем использовать следующее:

use feature qw( state );

use Cpanel::JSON::XS qw( );

sub key {
   state $encoder = Cpanel::JSON::XS->new->canonical;
   return $encoder->encode($_[0]);
}
2 голосов
/ 17 января 2020

Пожалуйста, убедитесь, что следующий кусок удовлетворяет вашим требованиям

#!/usr/bin/perl

use strict;
use warnings;
use feature 'say';

use Data::Dumper;

my @result;
my %seen;

my @arr = ({
  CONTEXTID => 1230,
  NAME => 'test8824',
  PROVIDERID => 163
}, {
  CONTEXTID => 8824,
  NAME => 'test8824',
  PROVIDERID => 77
}, {
  CONTEXTID => 8824,
  NAME => 'test8824',
  PROVIDERID => 779
}, {
  CONTEXTID => 8824,
  NAME => 'test8824',
  PROVIDERID => 141
}, {
  CONTEXTID => 1230,
  NAME => 'test8824',
  PROVIDERID => 163
});

foreach my $el ( @arr ) {
    my $k = join('|', @$el{qw/CONTEXTID NAME PROVIDERID/ });
    push @result, $el unless $seen{$k};
    $seen{$k} = 1;
}

print Dumper(\@result);

Вывод:

$VAR1 = [
          {
            'PROVIDERID' => 163,
            'CONTEXTID' => 1230,
            'NAME' => 'test8824'
          },
          {
            'NAME' => 'test8824',
            'CONTEXTID' => 8824,
            'PROVIDERID' => 77
          },
          {
            'CONTEXTID' => 8824,
            'PROVIDERID' => 779,
            'NAME' => 'test8824'
          },
          {
            'NAME' => 'test8824',
            'CONTEXTID' => 8824,
            'PROVIDERID' => 141
          }
        ];
0 голосов
/ 21 января 2020

В одном из ответов на stackoverflow я получил это решение, которое работает для меня, я не помню первоначальную мысль поста.

 my %seen;
 my @array;
 @array =  grep { my $e = $_; my $key = join '___', map { $e->{$_}; } sort keys %$_;!$seen{$key}++ } @array;

поместите ваш массив href в переменную array, и возвращенный массив будет иметь уникальные значения га sh.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...