2010-11-04 8 views
8

J'ai un fichier csv de 40 Mo avec 50 000 enregistrements. C'est une liste de produits géante. Chaque rangée a près de 20 champs. [Item #, UPC, Desc, etc.]Script pour trouver des doublons dans un fichier csv

Comment puis-je,

a) Trouver et imprimer des lignes en double. [Ce fichier est un grand fichier ajouté, j'ai donc plusieurs en-têtes inclus dans le fichier que je dois supprimer, donc je voulais connaître les lignes exactes qui sont en double.]

b) Trouver et imprimer des lignes dupliquées en fonction de une colonne. [Voir si un UPC est assigné à plusieurs produits]

J'ai besoin d'exécuter la commande ou le script sur le serveur et j'ai installé Perl et Python. Même bash script ou commande va travailler pour moi aussi.

Je n'ai pas besoin de préserver l'ordre des lignes. etc

J'ai essayé,

sorte largefile.csv | uniq -d

Pour obtenir les doublons, mais je ne reçois pas la réponse attendue.

Idéalement, je voudrais bash script ou commande, mais si quelqu'un a d'autres suggestions, ce serait génial aussi.

Merci


Voir: Remove duplicate rows from a large file in Python sur débordement de la pile

+5

pourquoi 'uniq -d' ne vous donne-t-il pas la réponse attendue? – dogbane

+0

Vous devez afficher quelques exemples de données (nettoyés si nécessaire), y compris ce que vous considérez comme des doublons et des non-doublons. Plus précisément, si le premier champ (item #) est différent, mais le deuxième champ (UPC) est le même ou si l'ensemble du dossier est le même, etc. Vous devriez également être plus précis sur ce que "je ne reçois pas la réponse attendue " veux dire. 'uniq' ne regarde la ligne entière que si vous lui dites d'omettre une partie de la ligne (mais elle n'utilise pas de virgules comme séparateurs de champs). En outre, les fichiers CSV peuvent être difficiles à traiter à moins que vous n'utilisiez des outils conçus à cet effet (par exemple, une librairie Python). –

Répondre

2

Vous pouvez éventuellement utiliser shell SQLite pour importer votre fichier csv et créer des index pour effectuer des commandes SQL plus rapidement.

8

Trouver et imprimer des lignes en double en Perl:

perl -ne 'print if $SEEN{$_}++' < input-file 

Trouvez et lignes d'impression avec des colonnes en double en Perl - disons la 5ème colonne où les champs sont séparés par des virgules:

perl -F/,/ -ane 'print if $SEEN{$F[4]}++' < input-file 
+0

Il vaut la peine de noter ce dernier travail si et seulement si les données CSV ne contiennent jamais un séparateur entre guillemets '1,2 ', 3,3', 4'. – RedGrittyBrick

+0

@mob: Il semble que pour tout groupe de lignes dupliquées, la dernière ligne n'est pas imprimée avec cet exemple. –

0

Pour la deuxième partie: lisez le fichier avec Text :: CSV dans un hachage sur votre clé (s) unique (s), vérifiez s'il existe une valeur pour le hachage avant de l'ajouter.Quelque chose comme ceci:

données (n'a pas besoin d'être triés), dans cet exemple, nous avons besoin des deux premières colonnes à être unique:

1142,X426,Name1,Thing1 
1142,X426,Name2,Thing2 
1142,X426,Name3,Thing3 
1142,X426,Name4,Thing4 
1144,X427,Name5,Thing5 
1144,X427,Name6,Thing6 
1144,X427,Name7,Thing7 
1144,X427,Name8,Thing8 

Code:

use strict; 
use warnings; 
use Text::CSV; 

my %data; 
my %dupes; 
my @rows; 
my $csv = Text::CSV->new() 
         or die "Cannot use CSV: ".Text::CSV->error_diag(); 

open my $fh, "<", "data.csv" or die "data.csv: $!"; 
while (my $row = $csv->getline($fh)) { 
    # insert row into row list 
    push @rows, $row; 
    # join the unique keys with the 
    # perl 'multidimensional array emulation' 
    # subscript character 
    my $key = join($;, @{$row}[0,1]); 
    # if it was just one field, just use 
    # my $key = $row->[$keyfieldindex]; 
    # if you were checking for full line duplicates (header lines): 
    # my $key = join($;, @$row); 
    # if %data has an entry for the record, add it to dupes 
    if (exists $data{$key}) { # duplicate 
     # if it isn't already duplicated 
     # add this row and the original 
     if (not exists $dupes{$key}) { 
      push @{$dupes{$key}}, $data{$key}; 
     } 
     # add the duplicate row 
     push @{$dupes{$key}}, $row; 
    } else { 
     $data{ $key } = $row; 
    } 
} 

$csv->eof or $csv->error_diag(); 
close $fh; 
# print out duplicates: 
warn "Duplicate Values:\n"; 
warn "-----------------\n"; 
foreach my $key (keys %dupes) { 
    my @keys = split($;, $key); 
    warn "Key: @keys\n"; 
    foreach my $dupe (@{$dupes{$key}}) { 
     warn "\tData: @$dupe\n"; 
    } 
} 

Quelles impressions quelque chose comme ceci:

Duplicate Values: 
----------------- 
Key: 1142 X426 
    Data: 1142 X426 Name1 Thing1 
    Data: 1142 X426 Name2 Thing2 
    Data: 1142 X426 Name3 Thing3 
    Data: 1142 X426 Name4 Thing4 
Key: 1144 X427 
    Data: 1144 X427 Name5 Thing5 
    Data: 1144 X427 Name6 Thing6 
    Data: 1144 X427 Name7 Thing7 
    Data: 1144 X427 Name8 Thing8 
8

Effectuez les opérations suivantes:

# Sort before using the uniq command 
sort largefile.csv | sort | uniq -d 

uniq est une commande très simple et ne signale que l'unicité/doublons qui sont à côté de l'autre.

+0

vous avez deux fois trier. – tmow

+0

Je l'ai édité. – tmow

+0

J'ai aussi essayé la version perl ici et c'est plus rapide que ça, au moins dans ubuntu shell sur windows10. Mais les deux fonctionnent très bien – user2548436

1

Voici mon script (très simple) pour le faire avec Ruby & Rake Gem.

d'abord créer un RakeFile et écrire ce code:

namespace :csv do 
    desc "find duplicates from CSV file on given column" 
    task :double, [:file, :column] do |t, args| 
    args.with_defaults(column: 0) 
    values = [] 
    index = args.column.to_i 
    # parse given file row by row 
    File.open(args.file, "r").each_slice(1) do |line| 
     # get value of the given column 
     values << line.first.split(';')[index] 
    end 
    # compare length with & without uniq method 
    puts values.uniq.length == values.length ? "File does not contain duplicates" : "File contains duplicates" 
    end 
end 

ensuite l'utiliser sur la première colonne

$ rake csv:double["2017.04.07-Export.csv"] 
File does not contain duplicates 

Et pour l'utiliser sur le second (par exemple)

$ rake csv:double["2017.04.07-Export.csv",1] 
File contains duplicates 
Questions connexes