staging.inyokaproject.org

Für diese Funktion musst du eingeloggt sein.

Mit AWK verschiedene Felder verschiedener Zeilen vergleichen

Status: Ungelöst | Ubuntu-Version: Ubuntu 14.04 (Trusty Tahr)
Antworten |

andreasandy

Anmeldungsdatum:
24. Dezember 2017

Beiträge: 3

Hallo alle zusammen!

Bei folgender Aufgabe komme ich nicht weiter. Hier ist der zu verarbeitende Inhalt einer Datei (die Zeilennummern gehören nicht zum Inhalt, nur für die nachfolgende Erläuterung der Aufgabenstellung):

01. AAA;AAB;10
02. AAB;AAA;12
03. AAA;FAC;26
04. AAA;FAV;15
05. DAD;HHZ;89
06. AAA;HOI;33
07. AAA;MKP;59
08. AAA;PPT;45
09. AAA;RRR;88
10. AAA;TTQ;87
11. HHZ;DAD;89
12. MKP;AAA;59

Diese Datei muss eingelesen werden, ausgegeben müssen alle vorhandenen Zeilen und die Zeilen, wo $1 der Zeile n nicht gleich $2 der Zeile m ist und $2 der Zeile n nicht gleich $1 der Zeile m ist, und in dieser Reihenfolge: $2;$1;$3.

Also, Zeile 1 und Zeile 2 müssen nicht angefasst werden, weil da findet man in beiden Zeilen Werte AAA und AAB, nur verdreht. Genauso Zeile 5 und Zeile 11, und Zeile 7 und Zeile 12. Alle anderen Zeilen haben sozusagen, keine gespiegelten "Doppelgänger" und für Sie muss so ein "Doppelgänger" generiert und der Datei hinzugefügt werden (an welcher Stelle, spielt keine Rolle).

Das ist der gewünschte Output:

01. AAA;AAB;10
02. AAB;AAA;12
03. AAA;FAC;26
04. AAA;FAV;15
05. DAD;HHZ;89
06. AAA;HOI;33
07. AAA;MKP;59
08. AAA;PPT;45
09. AAA;RRR;88
10. AAA;TTQ;87
11. HHZ;DAD;89
12. MKP;AAA;59
13. FAC;AAA;26
14. FAV;AAA;15
15. HOI;AAA;33
16. PPT;AAA;45
17. RRR;AAA;88
18. TTQ;AAA;87

Könnte mir bitte jemand helfen? Alle meine Versuche bleiben bisher erfolglos. Muss auch nicht unbedingt mit AWK erledigt werden. Danke!

Bearbeitet von Developer92:

Bitte verwende in Zukunft unsere Syntax. Wir haben zudem auch einen Vorschaubutton ☺

Marc_BlackJack_Rintsch Team-Icon

Ehemalige
Avatar von Marc_BlackJack_Rintsch

Anmeldungsdatum:
16. Juni 2006

Beiträge: 4735

In Perl:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
#!/usr/bin/env perl
use strict;
use warnings;

my $DELIMITER = ';';
my %pairs;

while (<>) {
    if ($_) {
        my ($a, $b, $c) = split /$DELIMITER/;
        if (exists $pairs{$b, $a}) {
            delete $pairs{$b, $a};
        } else {
            $pairs{$a,$b} = [$b, $a, $c];
        }
        print;
    }
}

print join($DELIMITER, @$_) foreach (values %pairs);

Testlauf:

$ perl test.pl < test2.csv | nl
     1  AAA;AAB;10
     2  AAB;AAA;12
     3  AAA;FAC;26
     4  AAA;FAV;15
     5  DAD;HHZ;89
     6  AAA;HOI;33
     7  AAA;MKP;59
     8  AAA;PPT;45
     9  AAA;RRR;88
    10  AAA;TTQ;87
    11  HHZ;DAD;89
    12  MKP;AAA;59
    13  RRR;AAA;88
    14  PPT;AAA;45
    15  FAC;AAA;26
    16  HOI;AAA;33
    17  TTQ;AAA;87
    18  FAV;AAA;15

kB Team-Icon

Supporter, Wikiteam
Avatar von kB

Anmeldungsdatum:
4. Oktober 2007

Beiträge: 9837

Einfach alle gespiegelten Doppelgänger erzeugen und die dann doppelt vorhandenen Doppelgänger wegwerfen. Das geht gut mit sort | uniq oder auch mit sort -u:

awk -F";" -v OFS=";" '{print ; print $2, $1, $3}' test.csv | sort -u 

track

Avatar von track

Anmeldungsdatum:
26. Juni 2008

Beiträge: 7174

Hi andreasandy,

zuerst mal herzlich willkommen hier auf dem Forum !

Nun ... mit assoziativen Arrays (wie so oft in solchen Fällen), auch unter awk, geht das recht hübsch:

track@track:~$ echo '01. AAA;AAB;10
AAB;AAA;12
AAA;FAC;26
AAA;FAV;15
DAD;HHZ;89
AAA;HOI;33
AAA;MKP;59
AAA;PPT;45
AAA;RRR;88
AAA;TTQ;87
HHZ;DAD;89
MKP;AAA;59'  |  awk -F';' '{OFS=FS; if(z[$1 ";" $2]) delete z[$1 ";" $2]; else z[$2 ";" $1]=$3; print}
 END {for (i in z) if(z[i]) print i,z[i]}'
AAA;AAB;10
AAB;AAA;12
AAA;FAC;26
AAA;FAV;15
DAD;HHZ;89
AAA;HOI;33
AAA;MKP;59
AAA;PPT;45
AAA;RRR;88
AAA;TTQ;87
HHZ;DAD;89
MKP;AAA;59
TTQ;AAA;87
HOI;AAA;33
FAC;AAA;26
PPT;AAA;45
FAV;AAA;15
RRR;AAA;88 

Hier nochmal, mit Erklärbär:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
BEGIN {    FS=";" ;                        # Spaltentrenner für Eingang
           OFS=FS    }                     # und Ausgang

      {    if(z[$1 ";" $2])                # Wenn ein Gegen-Eintrag zu den ersten beiden Spalten da ist:
               delete z[$1 ";" $2];          # prima: jetzt erledigt, löschen
           else                            # sonst:
               z[$2 ";" $1]=$3;              # merk Dir den Wert, mit vertauschten Spalten
               print   }                     # und druck die Zeile

END   {    for (i in z)                    # am Ende klappere alle Einträge ab -
               if(z[i])                      # wenn sie nicht leer sind:
                   print i,z[i]    }           # drucke Index (= Spalten 2+1) und Wert (= Spalte 3)

LG, und fröhliche Weihnachten noch !

track

p.s.:
kB schrieb:

Einfach alle gespiegelten Doppelgänger erzeugen und die dann doppelt vorhandenen Doppelgänger wegwerfen.

Die Idee ist geradezu genial einfach ! - einen Schattenpunkt könnte es allerdings geben: wenn die 3. Spalte bei einem Pärchen nicht gleich ist, bleiben die Einträge doppelt stehen.
(allerdings wissen wir nicht, was die 3. Spalte bedeutet: ob das überhaupt eine Rolle spielt)

andreasandy

(Themenstarter)

Anmeldungsdatum:
24. Dezember 2017

Beiträge: 3

Hallo track, vielen herzlichen Dank für die Super-Lösung, für die Erklärung und für die Weihnachtswünsche! Das Thema mit assoziativen und mehrdimensionalen Arrays muss ich mir noch genau anschauen.

An kB: ich danke Dir, dass Du auch diesen eleganten Vorschlag gemacht hast, nur, wie track auch sagte, muss die dritte Spalte bei einem Paar nicht unbedingt einen und denselben Wert haben.

Ich wünsche Euch schöne Feiertage und einen guten Start ins neue Jahr!

andreasandy

(Themenstarter)

Anmeldungsdatum:
24. Dezember 2017

Beiträge: 3

Marc_BlackJack_Rintsch schrieb:

In Perl:

Hallo Marc_BlackJack_Rintsch, vielen Dank für Deine Lösung! Mit Perl hatte ich schon seit langem nichts gemacht, werde mir Deine Lösung auf jeden Fall anschauen und testen! Ich wünsche Dir einen guten Start ins Neue Jahr!

Antworten |