2011-05-04 20 views
6

Estoy tratando de imprimir líneas duplicadas desde el manejador de archivos, no eliminarlas o cualquier otra cosa que vea en otras preguntas. No tengo suficiente experiencia con Perl para poder hacer esto rápidamente, así que estoy preguntando aquí. ¿Cuál es la manera de hacer esto?Perl - Encontrar líneas duplicadas en un archivo o matriz

+2

Mucho depende del tamaño de la entrada, tamaños de líneas y el número potencial de duplicados. Si los requisitos de memoria son bajos, las soluciones con hash '% duplicates' son adecuadas. –

+0

Ellos son. Solo estoy usando el identificador de archivo para comprobar rápidamente algo. No parece que haya ningún duplicado, eso está bien. – Chris

Respuesta

22

Utilizando las abreviaturas estándar de Perl:

my %seen; 
while (<>) { 
    print if $seen{$_}++; 
} 

Como "de una sola línea":

perl -ne 'print if $seen{$_}++' 

Más datos? Esto imprime <file name>:<line number>:<line>:

perl -ne 'print ($ARGV eq "-" ? "" : "$ARGV:"), "$.:$_" if $seen{$_}++' 

Explicación de %seen:

  • %seen declara un hash. Para cada única línea de en la entrada (que viene de while(<>) en este caso) $seen{$_} tendrá una ranura para escalar en el hash nombrado por el texto de la línea (esto es lo que $_ está haciendo en el tiene {} llaves).
  • Usando el operador de incremento de sufijo (x++) nos tomamos el valor de nuestra expresión, recordando a la subasta después de la expresión. Entonces, si no hemos "visto" la línea $seen{$_} no está definida, pero cuando se la fuerza a un "contexto" numérico como este, se toma como 0 - y como falso.
  • entonces es incrementado a 1.

Por lo tanto, cuando el while se pone en marcha, todas las líneas son "cero" (si ayuda a que se pueda imaginar las líneas como "no %seen"), entonces, el primer Cuando veamos una línea, perl toma el valor indefinido - que falla el if - e incrementa el recuento en la ranura escalar a 1. Por lo tanto, es 1 para cualquier ocurrencia futura en que punto pase la condición if y se imprima.

Ahora como dije anteriormente, %seen declara un hash, pero con strict desactivado, cualquier expresión variable puede crearse en el acto. Así que la primera vez que Perl ve $seen{$_} sabe que estoy buscando %seen, no lo tiene, por lo que lo crea.

Otra cosa interesante acerca de esto es que al final, si te interesa usarlo, tienes un recuento de cuántas veces se repitió cada línea.

+0

+1 nice one-liner – mcgrailm

+0

¿Puede explicar cómo funciona $ seen {$ _} ++ exactamente? Entiendo que está asignando el valor de la línea actual a una tabla hash, pero ¿qué hace el ++ aquí que lo hace encontrar duplicados? – Chris

+1

$ seen {$ _} se refiere a un valor en el hash% visto, con la clave $ _, que es la línea actual. El operador ++ incrementará el valor hash. Esto significa que la primera vez que aparece una tecla, su valor será falso y la impresión no se realizará. Las siguientes veces que se ve, será> 0, y así se ejecutará la impresión, e imprime sin args por defecto imprime la variable $ _. – TLP

3

probar esto

#!/usr/bin/perl -w 
use strict; 
use warnings; 

my %duplicates; 
while (<DATA>) { 
    print if !defined $duplicates{$_}; 
    $duplicates{$_}++; 
} 
+0

Haría 'imprimir a menos que haya $ duplicados {$ _}'. Y +1 para '-w',' use strict' y 'use warnings'. – Blrfl

0

Si usted tiene un sistema similar a Unix, puede utilizar uniq:

uniq -d foo 

o

uniq -D foo 

debe hacer lo que quiera. Más información: man uniq.

2

imprime dupes sólo una vez:

perl -ne "print if $seen{$_}++ == 1" 
+1

Esto es como 'sort file.txt | uniq -d' (solo imprime duplicados) en un shell típico de Unix. ¿Hay un simple equivalente de 'sort file.txt | uniq -u' (imprimir solo líneas únicas)? –

Cuestiones relacionadas