comparar múltiples hashes para valores de combinación de claves comunes

Tengo un poco de código de trabajo aquí donde estoy comparando las claves de seis hashes para encontrar las que son comunes entre todos ellos. Luego combino los valores de cada hash en un valor en un nuevo hash. Lo que me gustaría hacer es hacer esto escalable. Me gustaría poder pasar fácilmente de comparar 3 hashes a 100 sin tener que volver a mi código y modificarlo. ¿Alguna idea sobre cómo lograría esto? El resto del código ya funciona bien para diferentes cantidades de entrada, pero esta es la parte que me tiene atascado.

my $comparison = List::Compare->new([keys %{$posHashes[0]}], [keys %{$posHashes[1]}], [keys %{$posHashes[2]}], [keys %{$posHashes[3]}], [keys %{$posHashes[4]}], [keys %{$posHashes[5]}]);
my %comboHash;
for ($comparison->get_intersection) {
$comboHash{$_} = ($posHashes[0]{$_} . $posHashes[1]{$_} . $posHashes[2]{$_} . $posHashes[3]{$_} . $posHashes[4]{$_} . $posHashes[5]{$_});
}

preguntado el 03 de julio de 12 a las 23:07

Simplemente cree una subrutina y pásele referencias hash, luego puede hacer fácilmente el bucle necesario dentro de ella. P.ej my @hashes = @_; for my $href (@hashes) { ... }. -

4 Respuestas

my %all;
for my $posHash (@posHashes) {
   for my $key (keys(%$posHash)) {
      push @{ $all{$key} }, $posHash->{$key};
   }
}

my %comboHash;
for my $key (keys(%all)) {
   next if @{ $all{$key} } != @posHashes;
   $comboHash{$key} = join('', @{ $all{$key} });
}

Respondido 04 Jul 12, 00:07

No está claro qué significa "Estoy comparando las claves de seis hashes para encontrar las que son comunes entre todas". Lo interpreté en el sentido de que estás buscando claves comunes a todos los hashes. Si eso significa que desea comparar los valores en esas teclas, solo necesita cambiar el next línea. - Ikegami

Simplemente haga una subrutina y pásela referencias hash

my $combination = combine(@posHashes);

sub combine {
    my @hashes = @_;
    my @keys;
    for my $href (@hashes) {
        push @keys, keys %$href;
    }
    # Insert intersection code here..
    # .....
    my %combo;
    for my $href (@hashes) {
        for my $key (@intersection) {
            $combo{$key} .= $href->{$key};
        }
    }
    return \%combo;
}

Respondido 04 Jul 12, 00:07

Crear una subrutina:

sub combine_hashes {
  my %result = ();
  my @hashes = @_;
  my $first = shift @hashes;
  for my $element (keys %$first) {
    my $count = 0;
    for my $href (@hashes) {
      $count += (grep {$_ eq $element} (keys %$href));
    }
    if ($count > $#hashes) {
      $result{$element} = $first->{$element};
      $result{$element} .= $_->{$element} for @hashes;
    }
  }
  \%result;
}

y llámalo por:

my %h = %{combine_hashes(\%h1, \%h2, \%h3)};

...o como:

my %h = %{combine_hashes(@posHashes)};

Respondido 04 Jul 12, 00:07

Hay una solución bastante sencilla:

sub merge {
    my $first = shift;
    my @hashes = @_;
    my %result;
    KEY:
    for my $key (keys %$first) {
        my $accu = $first->{$key};
        for my $hash (@hashes) {
            next KEY unless exists $hash->{$key};
            $accu .= $hash->{$key};
        }
        $result{$key} = $accu;
    }
    return \%result;
}

Debe llamarlo con referencias a hashes y también devolverá una referencia de hash, por ejemplo:

my $comboHashRef = merge(@posHashes);

Respondido 04 Jul 12, 22:07

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.