Encontre o valor da coluna duplicada em CSV

Encontre o valor da coluna duplicada em CSV

Estou tentando encontrar IDs duplicados em um arquivo CSV grande, há apenas registros por linha, mas a condição para encontrar uma duplicata será a primeira coluna.<id>,<value>,<date>

exemplo.csv

11111111,high,6/3/2019
22222222,high,6/3/2019
33333333,high,6/3/2019
11111111,low,5/3/2019
11111111,medium,7/3/2019

Saída desejada:

11111111,high,6/3/2019
11111111,low,5/3/2019
11111111,medium,7/3/2019

Nenhuma ordem é necessária para a saída.

Responder1

Usando AWK:

awk -F, 'data[$1] && !output[$1] { print data[$1]; output[$1] = 1 }; output[$1]; { data[$1] = $0 }'

Isso analisa cada linha e se comporta da seguinte maneira:

  • se já vimos o valor na primeira coluna, observe que devemos gerar qualquer linha correspondente e exibir a linha memorizada;
  • produza a linha atual se sua primeira coluna corresponder à que desejamos gerar;
  • armazene a linha atual digitada na primeira coluna.

Responder2

Se todos os seus IDs tiverem o mesmo comprimento (8 caracteres no seu exemplo), você poderá fazer tudo usando sorte GNU uniq:

$ sort file | uniq -Dw 8
11111111,high,6/3/2019
11111111,low,5/3/2019
11111111,medium,7/3/2019

Se eles não tiverem o mesmo comprimento, você ainda poderá usar esta abordagem, mas fica um pouco mais complicado:

$ tr ',' ' ' < file | sort  | rev | uniq -f2 -D | rev | tr ' ' ','
11111111,high,6/3/2019
11111111,low,5/3/2019
11111111,medium,7/3/2019

Responder3

awk -F, '$1 in m { print m[$1]$0; m[$1]=""; next } 
                 { m[$1]=$0 "\n" }' ex

Responder4

Isso pode ser feito usando GNU sedsuas construções de regex estendidas. Primeiro carregamos o arquivo no espaço padrão e, em seguida, removemos quaisquer linhas não repetidas do início do espaço padrão. Além disso, uma bandeira, \n\n, é colocada no final do espaço do padrão, onde lançamos as linhas repetidas. Então, uma vez que esse sinalizador borbulha até o início do espaço do padrão => a operação termina e agora podemos prosseguir e remover os marcadores do espaço do padrão e imprimir no stdout.

$ sed -Ee '
   $!{
      N;s/^/\n/
      $s/$/\n\n/;D
   }
   /^([^,\n]*),[^\n]*\n(.*\n)?\1,/!D
   s/^([^\n]*)(.*)/\2\1\n/;/^\n\n/!D
   s/^\n\n//;s/\n$//
' inp

Esta é uma POSIX-sedversão E outra maneira de abordar o problema em que não mantemos o arquivo inteiro em nenhum momento no padrão ou nos espaços de retenção. Assim que uma linha duplicada é vista, ela é impressa em stdout E a linha de referência é marcada e impressa, marcada porque não queremos imprimi-la na próxima vez que sua duplicata for vista.

$ sed -ne '
   H;g;y/\n_/_\n/
   /.*_\([^,_]*\)\(,[^_]*\)\[0]_\(.*_\)\{0,1\}\1,[^_]*$/{
      s//\1\2/;y/_\n/\n_/;p
      g;s/.*\n//p;g;y/\n_/_\n/
      s/\(.*_\([^,_]*\),[^_]*\)\[0]\(_\(.*_\)\{0,1\}\)\2,[^_]*$/\1[1]\3/
      s/_$//;y/_\n/\n_/;bh
   }
   /.*_\([^,_]*\)\(,[^_]*\)\[1]_\(.*_\)\{0,1\}\1,[^_]*$/{
      s/.*_//;y/_\n/\n_/;p
      g;s/\(.*\)\n.*/\1/;bh
   }
   y/_\n/\n_/;s/$/[0]/;:h;h
' inp

Esta é uma Perlsolução baseada para o problema onde mantemos as linhas em um hash de array. Assim que vemos uma linha repetida, imprimimos o array e também o esvaziamos, e também imprimimos a linha duplicada.

$ perl -F, -lane '
   push(@{$h{$F[0]}},$_),next if ! exists $h{$F[0]};
   print for splice(@{$h{$F[0]}}),$_;
' inp

Saída:

11111111,high,6/3/2019
11111111,low,5/3/2019
11111111,medium,7/3/2019

informação relacionada