#!/usr/bin/perl
use strict;
use warnings;
######################################################
# Funktionen #
##############
# Liste einlesen
# Werte:
# > Name des ersten Eintrages
# > Name des zweiten Eintrages
# > Name des dritten Eintrages
# > Filehandle
# < gelesenen Liste
sub parse_liste($$$$)
{
my ($erst,$dann,$letzt,$fh)=@_;
my @liste=();
while(my $l=<$fh>)
{ push(@liste,{$erst=>[$1], $dann=>[$2], $letzt=>[$3]}) if($l=~/^([^\s]+)\s+(\d+)\s+([^\s]+)$/); }
return @liste;
}
# Einträge zusammenfassen
# Werte:
# > die Hashrefferenz
# > Name des Wertes, dessen Ihnalt zusammengefst werden soll
# < String, der die vereinte liste enthält.
sub myjoin($$)
{
my ($ref,$name)=@_;
# ich benutze hier den "Nullsring" als Trenner,
# da er normalerweise niemals in einem String vorkommt
return join("\000", @{$ref->{$name}});
}
# Werte vergelichen (als Aufruf aus "sort" heraus)
# Werte:
# > erste Hashreferenz
# > zweite Hashreferenz
# > Name des primären Sortierwertes
# > Name des sekundären Sortierwertes
# > Name des terziären Sortierwertes
sub vergleiche($$$$$)
{
my ($wa,$wb,$erst,$dann,$letzt)=@_;
if( myjoin($wa,$erst) eq myjoin($wb,$erst) )
{
return myjoin($wa,$letzt) cmp myjoin($wb,$letzt) if( myjoin($wa,$dann) eq myjoin($wb,$dann) );
return myjoin($wa,$dann) cmp myjoin($wb,$dann);
}
return myjoin($wa,$erst) cmp myjoin($wb,$erst);
}
# Liteneinträge zusammenfassen
# Werte:
# > Name des ersten Wertes der übereinstimmen muss
# > Name des zweiten Wertes der übereinstimmen muss
# > Name des Wertes der bei positiver Prüfung zusammengefasst wird
# < zusammengefasste Liste
sub komibiere($$$@)
{
my ($erst,$dann,$letzt,@liste)=@_;
# erstmal sortieren
@liste=sort{ vergleiche($a,$b,$erst,$dann,$letzt) }@liste;
# ein Eintrag kommt immer in die Ausgabeliste
my @liste_k=({ $erst => $liste[0]->{$erst}, $dann => $liste[0]->{$dann}, $letzt => $liste[0]->{$letzt} });
shift(@liste);
# Die Eingabeliste durcharbeiten
while(@liste)
{
my $eintrag=shift(@liste);
if(
myjoin($eintrag,$erst) eq myjoin($liste_k[-1],$erst) &&
myjoin($eintrag,$dann) eq myjoin($liste_k[-1],$dann)
)
{ push(@{$liste_k[-1]->{$letzt}},@{$eintrag->{$letzt}}); }
else
{ push(@liste_k,{ $erst=>$eintrag->{$erst}, $dann=>$eintrag->{$dann}, $letzt=>$eintrag->{$letzt} }); }
}
return @liste_k;
}
# Listeneinträge ausgeben
# Werte:
# > Name des ersten Eintrages
# > Name des zweiten Eintrages
# > Name des dritten Eintrages
sub my_print($$$@)
{
my ($erst,$dann,$letzt,@l)=@_;
print '/','#'x32,"\\\n";
printf("|%10s|%10s|%10s|\n",$erst,$dann,$letzt);
print '+','-'x10,'+','-'x10,'+','-'x10,"+\n";
for my $i (@l)
{
my $e= join(',',@{$i->{$erst}});
my $d= join(',',@{$i->{$dann}});
my $l= join(',',@{$i->{$letzt}});
printf("|%10s|%10s|%10s|\n",$e,$d,$l);
}
print '\\','#'x32,"/\n";
}
######################################################
# Programm #
############
my @l=parse_liste('quelle','port','ziel',*DATA);
print "Rohdaten\n";
my_print('quelle','port','ziel',@l);
print "\"Ports\" zusammengefasst\n";
@l=komibiere('quelle','ziel','port',@l);
my_print('quelle','port','ziel',@l);
print "\"Quellen\" zusammengefasst\n";
@l=komibiere('ziel','port','quelle',@l);
my_print('quelle','port','ziel',@l);
print "\"Ziele\" zusammengefasst\n";
@l=komibiere('quelle','port','ziel',@l);
my_print('quelle','port','ziel',@l);
exit(0);
######################################################
# DATAZEILEN #
##############
__DATA__
A 1 b
A 2 b
K 24 c
P 2 d
B 3 b
B 1 b
B 22 a
K 2 d
P 1 a
P 1 b
K 1 c
K 2 a
K 4 a
C 22 c
C 4 a
K 22 a
B 11 c
D 2 e
D 1 a
A 33 c
W 1 q
L 3 w
Z 11 q
W 11 q
Z 1 q
D 1 c
P 1 c