2010-12-01 12 views
4

Quel est le meilleur moyen de récapituler les données d'un fichier qui contient environ 2 millions d'enregistrements en Perl?Perl - Résumer les données dans le fichier

Pour exemple: Un fichier comme celui-ci,

ABC | XYZ | DEF | EGH | 100

ABC | XYZ | DEF | FGH | 200

SDF | GHT | WWW | RTY | 1000

SDF | GHT | WWW | TYU | 2000

doivent être résumés sur les 3 premières colonnes comme celui-ci,

ABC | XYZ | DEF | 300

SDF | GHT | WWW | 3000

Chris

+1

Vous voulez résumer le numéro dans la dernière colonne pour tous les enregistrements où les trois premières colonnes correspondent? – Sorpigal

Répondre

3

présumant qu'il y toujours cinq colonnes, dont la cinquième est numérique, et vous voulez toujours que les trois premières colonnes soient la clé ...

use warnings; 
use strict; 

my %totals_hash; 

while (<>) 
{ 
    chomp; 
    my @cols = split /\|/; 

    my $key = join '|', @cols[0..2]; 

    $totals_hash{$key} += $cols[4]; 
} 

foreach (sort keys %totals_hash) 
{ 
    print $_, '|', $totals_hash{$_}, "\n"; 
} 
+0

Merci, ça marche! – Chris

2

Vous pouvez utiliser un hachage comme:

my %hash; 
while (<DATA>) { 
     chomp; 
     my @tmp = split/\|/;  # split each line on | 
     my $value = pop @tmp; # last ele is the value 
     pop @tmp;    # pop unwanted entry 
     my $key = join '|',@tmp; # join the remaining ele to form key 

     $hash{$key} += $value; # add value for this key 
} 

# print hash key-values. 
for(sort keys %hash) { 
     print $_ . '|'.$hash{$_}."\n"; 
} 

Ideone link

+0

Maintenant, pour un peu plus difficile, – Chris

+0

Et s'il y avait plus d'une colonne à résumer? – Chris

+0

@Chris: S'il vous plaît mettre à jour la question avec un exemple. – codaddict

0

En supposant que votre fichier d'entrée a ses enregistrements dans des lignes séparées.

perl -n -e 'chomp;@a=split/\|/;$h{join"|",[email protected],0,3}[email protected];END{print map{"$_: $h{$_}\n"}keys%h}' < inputfile 
-1

Trier mettre tous les dossiers avec les mêmes 3 premiers triplés à côté de l'autre. Itérer et expulser un sous-total lorsqu'un ensemble différent de triplets apparaît.

$prevKey=""; 
$subtotal=0; 
open(INPUTFILE, "<$inFile"); 
@lines=<INPUTFILE>; 
close (INPUTFILE); 
open(OUTFILE, ">$outFile"); 
@sorted=sort(@lines); 
foreach $line(@lines){ 
    @parts=split(/\|/g, $line); 
    $value=pop(@parts); 
    $value-=0; #coerce string to a number 
    $key=$parts[0]."|".$parts[1]."|".$parts[2]; 
    if($key ne $prevKey){ 
     print OUTFILE "$prevKey|$subtotal\n"; 
     $prevKey=$key; 
     $subtotal=0; 
     } 
    $subtotal+=$value; 
    } 
close(OUTFILE); 

Si le tri de 2 millions de selfs votre boîte, vous pouvez avoir à mettre chaque enregistrement dans un fichier basé sur le groupe, puis faire le sous-total pour chaque fichier.

+0

-1. Pourquoi l'OP devrait-il être obligé de lire tout le fichier à la fois alors que tout peut être fait en une seule fois sans avoir tout en mémoire? –

+0

Désolé. Merci d'être charitable à ce sujet. Je n'essaye pas de te ding, juste la réponse. Je suis sûr que vous êtes une bonne personne et un bon programmeur dans l'ensemble. :-) –

+0

Mon mauvais, je rétracte le commentaire. Je vais apprendre à traiter correctement les fichiers. Merci pour la correction. :) – tschubring

0

1-2-3-4 Je déclare UNE GUERRE DE CODE-GOLF !!! (D'accord, un raisonnablement lisible code de golf poussière vers le haut.)

my %sums; 
m/([^|]+\|[^|]+\|[^|]+).*?\|(\d+)/ and $sums{ $1 } += $2 while <>; 
print join("\n", (map { "$_|$sums{$_}" } sort keys %sums), ''); 
Questions connexes