2011-07-09 6 views
6

Código:código Comprensión: Hash, grep de duplicados (modificados para verificar si hay múltiples elementos)

@all_matches = grep 
{ 
    ! ($seensentence 
    { 
     $_->[0] .'-'. $_->[1] .'-'. $_->[5] 
    } 
    ++) 
} 
@all_matches; 

Propósito: Este código elimina duplicados de ciertos elementos de la matriz @all_matches que es un AoA.

Mi intento de desglose completo (con ?? .. ?? alrededor de donde estoy seguro):

Grep devuelve los elementos de @all_matches que devuelven verdadero.

La clave del hash %seensentence es ?? los tres elementos ?? de @all_matches. Como un hash solo puede tener claves únicas, la primera vez en su valor se incrementa de undef (0) a 1. La próxima vez, es un valor definido, pero ! significa que grep lo devuelve solo si es undef (valor único asociado con ese elemento).


Mis preguntas:

(1) ¿Cómo se puede convertir en un {$_->[0] .'-'. $_->[1] .'-'. $_->[5]}++ I HoH?

Me dijeron que esta es otra forma (idiomática) de lograrlo. Una puñalada en la oscuridad sería:

({$_->[0] => 0, 
$_->[1] => 0, 
$_->[5] => 0})++ 

(1b) Debido No entiendo cómo el original está haciendo lo que yo quiero que haga. Leí que -bareword es equivalente a "-bareword" así que probé: {"$_->[0]" . "$_->[1]". "$_->[5]"} y parecía funcionar exactamente igual. Todavía no entiendo: ¿está tratando cada elemento como una clave (a) por separado (como un conjunto de teclas) o es (b) Corregir: todos simultáneamente (ya que . los concatena a todos en una cadena) o es (c) no hacer lo que creo que es?

(2) ¿Qué significa esto: $_->[0] || $_->[1] || $_->[5]? No hace lo mismo que arriba.

Leí que: los operadores lógicos de cortocircuito devuelven el último valor, por lo que verificaría un valor en {$_->[0]} y si hubiera uno, pensé que el valor allí se incrementaría, si no comprobaría el siguiente elemento hasta que ninguno fueron verdaderas, que es cuando grep pasa el valor único.


Gracias por su tiempo, yo tratamos de ser lo más completa posible (a una falla?), Pero quiero saber si hay algo que falta.

+0

Pregunta muy bien compuesta! – DavidO

Respuesta

5

Primero vamos a convertir el grep en un lazo foreach para que podamos examinarlo más claramente. Voy a expandir algunos de los modismos en construcciones más grandes en aras de la claridad.

my @all_matches = (...); 
{ 
    my %seen; 
    my @no_dupes; 
    foreach my $match (@all_matches) { 
     my $first_item = $match->[0]; 
     my $second_item = $match->[1]; 
     my $third_item = $match->[5]; 
     my $key = join '-', $first_item, $second_item, $third_item; 
     if(not $seen{ $key }++) { 
      push @no_dupes, $match; 
     } 
    } 
    @all_matches = @no_dupes; 
} 

En otras palabras, el codificador original, es la creación de una clave hash utilizando la referencia de matriz celebrada en $ partido, para cada uno de los índices referente de $match->[0], 1 y 5. Como las teclas hash son únicas, cualquier duplicado se eliminará al verificar si la clave ya existe antes de ingresar al @no_dupes.

El mecanismo grep{} es solo una expresión más eficiente en cuanto al código (es decir, más rápido para escribir, y sin variables desechables) para lograr lo mismo. Si funciona, ¿por qué refactorizarlo? ¿Qué no está haciendo eso que necesita mejorar?

a hacer lo mismo con un HoH, usted puede hacer esto:

my @all_matches = (...); 
{ 
    my %seen; 
    my @no_dupes; 
    foreach my $match (@all_matches) { 
     my $first_item = $match->[0]; 
     my $second_item = $match->[1]; 
     my $third_item = $match->[5]; 
     if(not $seen{ $first_item }->{ $second_item }->{ $third_item }++) { 
      push @no_dupes, $match; 
     } 
    } 
    @all_matches = @no_dupes; 
} 

que podría ser traducido de nuevo en un grep de la siguiente manera:

my @all_matches = (...); 
{ 
    my %seen; 
    @all_matches = grep { not $seen{$_->[0]}->{$_->[1]}{$_->[5]}++ } @all_matches; 
} 

Sin embargo, este es un caso en el que no veo una clara ventaja para construir una estructura de datos, a menos que intente utilizar %seen más tarde para otra cosa.

Con respecto al operador ||, ese es un animal diferente. No puedo pensar en ninguna forma útil de emplearlo en este contexto. El operador de cortocircuito lógico de, por ejemplo, "$a || $b || $c" prueba la veracidad booleana de $a. Si es verdad, devuelve su valor. Si es falso, comprueba $b de la misma manera. Si es falso, comprueba $c de la misma manera. Pero si $a es verdadero, $b nunca se verifica. Si $b es verdadero, $c nunca se verifica.

+0

Gracias, has afirmado todo lo que necesitaba, supongo que la pregunta principal es cómo la clave hash trata con una cadena. Entiendo '$ seen {$ one_item} ++' pero no entiendo cómo '$ seen {one_itemtwo_itemthree_item} ++' sería interpretado por un hash. – Jon

+0

$ first_item contiene el valor mantenido en $ match -> [0]. Entonces, cualquiera que sea ese valor se convierte en un componente de la clave de hash total, que en realidad es solo una cadena de todos modos. – DavidO

+0

Oh, entonces está haciendo una sola cuerda, con el contenido de cada elemento. Luego, si ve la tecla TOTAL exacta (es decir, los tres elementos son iguales: palabra1palabra2word3) cuenta como un duplicado, si incluso uno es diferente, es único. – Jon

4

La clave de $ seensentence es una cadena simple. Esa expresión $_->[0] .'-'. $_->[1] .'-'. $_->[5] construye una cadena. Aquí hay una expresión equivalente: join '-', $_->[0], $_->[1], $_->[5]. Parece suponer que los elementos 0, 1 y 5 son suficientes para identificar duplicados en @all_matches.

Editar
Falló su última pregunta.

$_->[0] || $_->[1] || $_->[5] vuelve

  • $_->[0]$_->[0] si no es falso (0, cadena vacía, no definido),
  • $_->[1]$_->[1] si no es falso,
  • $_->[5] lo contrario.

Los operadores de acceso directo se detienen tan pronto como tiene sentido detenerse. En el caso de ||, esto es tan pronto como el resultado sea un valor no falso. En el caso de &&, esto es tan pronto como el resultado sea falso.

+0

Gracias por la edición. No puedo entender cómo ninguno de los operadores '||' o '&&' no actúa igual que una cadena en la tecla hash. Creo que '&&' es lo que quiero verificar que los elementos 0, 1 y 5 sean duplicados. – Jon

+0

|| y && son operadores lógicos. No son lo que quieres. –

Cuestiones relacionadas