Diese Website existiert nur weil wir Werbung mit AdSense ausliefern.
Bitte den AdBlocker daher auf dieser Website ausschalten! Danke.

Mit AWK verschiedene Felder verschiedener Zeilen vergleichen

Alles rund um die verschiedenen Konsolen und shells sowie die Programmierung unter Linux

Moderator: Moderatoren

andreasandy
Newbie
Newbie
Beiträge: 13
Registriert: 25. Dez 2017, 00:06

Mit AWK verschiedene Felder verschiedener Zeilen vergleichen

Beitrag von andreasandy » 25. Dez 2017, 00:09

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!

Werbung:

Benutzeravatar
robi
Moderator
Moderator
Beiträge: 3160
Registriert: 25. Aug 2004, 02:13

Re: Mit AWK verschiedene Felder verschiedener Zeilen vergleichen

Beitrag von robi » 25. Dez 2017, 00:47

Code: Alles auswählen

awk  ' BEGIN{
        OFS=";"
        FS=";"
        };
        {x[$1,$2]=$3};
        END{for (i in x) {
                split(i,y,SUBSEP);
                print y[1],y[2],x[i]
                if (!((y[2],y[1]) in x)) {
                        print y[2],y[1],x[i]
                }
        };
}'    deine_testdatei
Aber frag nicht wie das funktioniert ;)
arbeiten mit mehrdimensionale Arrays in AWK sind nicht das einfachste und um das zu verstehen sollte man schon zumindest ein bisschen in AWK Dokus geblättert haben.

Nun gehe er und verkünde das freudig Ergebnis in all den Foren seines von Frevel geprägten Multiposts um weitere Versuche in dafür unbrauchbaren Sprachen frühzeitig zu beenden noch bevor die festlichen Tage ausgelaufen sind.

robi

Benutzeravatar
framp
Moderator
Moderator
Beiträge: 4270
Registriert: 6. Jun 2004, 20:57
Wohnort: bei Stuttgart
Kontaktdaten:

Re: Mit AWK verschiedene Felder verschiedener Zeilen vergleichen

Beitrag von framp » 25. Dez 2017, 20:19

Vielleicht interessiert es Dich ja wie ein Algorithmus in go aussehen könnte. Wie man schnell sieht geht es aber nicht so kurz und knapp wie in Robis awk Lösung :-/

Code: Alles auswählen

package main

import (
	"bufio"
	"fmt"
	"os"
	"strings"
)

const separator = ";"

// AAA;AAB;10
type key struct { // key into map of elements found in file
	key1 string // AAA
	key2 string // AAB
}

func (k key) String() string { // Stringer for key to print string representation of key
	return fmt.Sprintf("%s%s%s", k.key1, separator, k.key2)
}

func main() {

	elements := make(map[key]string) // value in map is last element 10
	n := 1                           // just a simple counter for all elements

	file, _ := os.Open("pair.dat") // read input data from file
	defer file.Close()             // make sure it's closed at end of prog

	scanner := bufio.NewScanner(file)
	for scanner.Scan() { // read file line by line
		    token := strings.Split(scanner.Text(), separator) // split line into 3 tokens separated by ;
		    k := key{token[0], token[1]}                      // build key AAA;AAB
		    elements[k] = token[2]                            // store value for key in map
		    fmt.Printf("%02d: %s;%s\n", n, k, token[2])       // just print the line read
		    n++
	}

	for e, _ := range elements { // loop over all elements
  		    reverseKey := key{e.key2, e.key1}       // build reverse key
		    if _, ok := elements[reverseKey]; !ok { // if reverse key does NOT exist
			        fmt.Printf("%02d: %s;%s\n", n, reverseKey, elements[e]) // print reverse key with value from key
			        n++
		    }
	}
}

/* Result of run:

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: RRR;AAA;88
14: FAC;AAA;26
15: HOI;AAA;33
16: PPT;AAA;45
17: TTQ;AAA;87
18: FAV;AAA;15

*/

andreasandy
Newbie
Newbie
Beiträge: 13
Registriert: 25. Dez 2017, 00:06

Re: Mit AWK verschiedene Felder verschiedener Zeilen vergleichen

Beitrag von andreasandy » 25. Dez 2017, 22:57

Hi Robi, vielen Dank für Deine Hilfe! Das funktioniert.
Ich werde mich mit dem Thema "mehrdimensionale Arrays" aufs Neue auseinander setzen.

An tomm.fa: danke für den Hinweis, ich habe das zur Kenntnis genommen.

andreasandy
Newbie
Newbie
Beiträge: 13
Registriert: 25. Dez 2017, 00:06

Re: Mit AWK verschiedene Felder verschiedener Zeilen vergleichen

Beitrag von andreasandy » 25. Dez 2017, 23:02

Hallo framp, ich danke Dir! Ich bin für alle Anregungen dankbar, da ich mich auf dem Lernpfad befinde.
Das ist interessant.

Benutzeravatar
framp
Moderator
Moderator
Beiträge: 4270
Registriert: 6. Jun 2004, 20:57
Wohnort: bei Stuttgart
Kontaktdaten:

Re: Mit AWK verschiedene Felder verschiedener Zeilen vergleichen

Beitrag von framp » 25. Dez 2017, 23:03

Und was ist mit meinem Vorschlag in go ? Schmoll :(

... just kidding ;) - go ist schon exotisch - hatte nur Lust das mal auszuprobieren

Benutzeravatar
framp
Moderator
Moderator
Beiträge: 4270
Registriert: 6. Jun 2004, 20:57
Wohnort: bei Stuttgart
Kontaktdaten:

Re: Mit AWK verschiedene Felder verschiedener Zeilen vergleichen

Beitrag von framp » 25. Dez 2017, 23:04

Sehe gerade dass sich unsere Posts überschnitten haben.

Alles gut :thumbs:

abgdf
Guru
Guru
Beiträge: 3111
Registriert: 13. Apr 2004, 21:15

Re: Mit AWK verschiedene Felder verschiedener Zeilen vergleichen

Beitrag von abgdf » 26. Dez 2017, 02:39

Perl mit Klassen:

Code: Alles auswählen

#!/usr/bin/perl

use warnings;
use strict;

package Line {

    sub new {
        my $classname = shift;
        my $self = {nr => shift,
                    first => shift,
                    second => shift,
                    third  => shift,
                    output  => 1};
        return bless($self, $classname);
    }

    sub check {
        my $self = shift;
        my $nr_in = shift;
        my $first_in = shift;
        my $second_in = shift;
        if ($self->{nr} eq $nr_in) {
            return;
        }
        if ($self->{first} eq $second_in &&
            $self->{second} eq $first_in) {
            $self->{output} = 0;
        }
    }

    sub checkandprint {
        my $self = shift;
        my $count = shift;
        if ($self->{output} == 1) {
            print "$count. ";
            print $self->{second};
            print ";";
            print $self->{first};
            print ";";
            print $self->{third};
            print "\n";
        }
    }
}
          
my @a = <DATA>;
my @lines = ();
my $i;
my $u;

my $n = 1;
my $count = 0;
foreach $i (@a) {
    chomp($i);
    $count++;
    if ($count < 10) {
        print "0";
    }
    print "$count. $i\n";
    my @b = split(/;/, $i);
    push (@lines, Line->new($n, $b[0], $b[1], $b[2]));
    $n++;
}

foreach $i (@lines) {
    foreach $u (@lines) {
        $i->check($u->{nr}, $u->{first}, $u->{second});
    }
}

foreach $i (@lines) {
    if ($i->{output} == 1) {
        $count++;
    }
    $i->checkandprint($count);
}

__DATA__
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

Benutzeravatar
robi
Moderator
Moderator
Beiträge: 3160
Registriert: 25. Aug 2004, 02:13

Re: Mit AWK verschiedene Felder verschiedener Zeilen vergleichen

Beitrag von robi » 26. Dez 2017, 11:41

Nur mal um die alten Kamelen mal wieder aufzuwärmen und zu den Feiertagen mal wieder ein bisschen schmunzeln in das eine oder andere Gesicht zu zaubern.
Sind ja in den verschiedenen Foren die unterschiedlichsten Lösungen eingetroffen. Sollte man sich mal die Zeit nehmen und die einzelnen Autoren versuchen in die Evolution eines Programmierers einzuordenen.
abgdf hat geschrieben:
26. Dez 2017, 02:39
Perl mit Klassen:
für den Chefprogrammierer reichst noch nicht ganz ;)

robi

abgdf
Guru
Guru
Beiträge: 3111
Registriert: 13. Apr 2004, 21:15

Re: Mit AWK verschiedene Felder verschiedener Zeilen vergleichen

Beitrag von abgdf » 26. Dez 2017, 15:01

robi hat geschrieben:
25. Dez 2017, 00:47
arbeiten mit mehrdimensionale Arrays in AWK sind nicht das einfachste und um das zu verstehen sollte man schon zumindest ein bisschen in AWK Dokus geblättert haben.
Eben, das ist in Perl auch so. Mit den Objekten komm' ich um die mehrdimensionalen Arrays 'rum (beides, OOP und AoA, ist überhaupt erst mit Perl 5 dazugekommen). Die Attribute in dem Objekt sind dann einfache Skalare.
Wenn man sich erstmal an die Klassendefinition gewöhnt hat, und daran, wie man auf Attribute und Methoden zugreift - was im Prinzip genau wie in Python funktioniert -, finde ich es leichter und übersichtlicher mit Objekten umzugehen als mit komplexen AoA oder HoH-Strukturen.
Schöne Weihnachten noch. :)

Benutzeravatar
framp
Moderator
Moderator
Beiträge: 4270
Registriert: 6. Jun 2004, 20:57
Wohnort: bei Stuttgart
Kontaktdaten:

Re: Mit AWK verschiedene Felder verschiedener Zeilen vergleichen

Beitrag von framp » 26. Dez 2017, 20:08

Netter Link von Dir Robi :thumbs:

Anbei noch eine bash Version :D.

Code: Alles auswählen

#!/bin/bash

declare -A map

while IFS=";" read -a e; do				# read elements and store in map
	map["${e[0]};${e[1]}"]=${e[2]}
done < pair.dat

n=1
for key in "${!map[@]}"; do				# process all elements
	e=(${key//;/ })						# split key elements
	reverseKey="${e[1]};${e[0]}"		# build reverse key
	echo "$n: $key;${map[$key]}"
	(( n++ ))
	if ! [[ ${map[$reverseKey]+x} ]]; then	# if reverse key does NOT exists
		echo "$n: $reverseKey;${map[$key]}"
		(( n++ ))
	fi
done

}-Tux-{
Hacker
Hacker
Beiträge: 698
Registriert: 12. Dez 2004, 19:54
Kontaktdaten:

Re: Mit AWK verschiedene Felder verschiedener Zeilen vergleichen

Beitrag von }-Tux-{ » 27. Dez 2017, 16:25

Hier mal ein kleiner perl Ein- bzw. Dreizeiler:

Code: Alles auswählen

perl -e 'my %h = map { $_ =~ s/^([^;]+);([^;]+);(.*)\n/$1;$2/r => "$3" } <>; print "$_;$h{$_}\n" for (sort(keys(%h))); print join(";", @$_) . "\n" for grep { !$h{$_->[0]} } map { [s/^([^;]+);([^;]+)$/$2;$1/r, $h{$_}] } sort(keys(%h));' filename
}-Tux-{

andreasandy
Newbie
Newbie
Beiträge: 13
Registriert: 25. Dez 2017, 00:06

Re: Mit AWK verschiedene Felder verschiedener Zeilen vergleichen

Beitrag von andreasandy » 28. Dez 2017, 18:48

framp hat geschrieben:
25. Dez 2017, 23:04
Sehe gerade dass sich unsere Posts überschnitten haben.

Alles gut :thumbs:
Hallo framp :-)

Ich habe nur vor ein Paar Tagen zum ersten Mal etwas über Go gehört. Steht nicht ganz oben auf meiner Prio-Liste, ich werde es mir aber bei Gelegenheit anschauen. Ich verspreche es Dir :-)

andreasandy
Newbie
Newbie
Beiträge: 13
Registriert: 25. Dez 2017, 00:06

Re: Mit AWK verschiedene Felder verschiedener Zeilen vergleichen

Beitrag von andreasandy » 28. Dez 2017, 18:49

abgdf hat geschrieben:
26. Dez 2017, 02:39
Perl mit Klassen:
....
Hallo abgdf,

vielen Dank für diesen Vorschlag! Auch interessant!

andreasandy
Newbie
Newbie
Beiträge: 13
Registriert: 25. Dez 2017, 00:06

Re: Mit AWK verschiedene Felder verschiedener Zeilen vergleichen

Beitrag von andreasandy » 28. Dez 2017, 18:53

framp hat geschrieben:
26. Dez 2017, 20:08
Netter Link von Dir Robi :thumbs:

Anbei noch eine bash Version :D.
Hallo framp!

Danke auch für die bash-Version!

andreasandy
Newbie
Newbie
Beiträge: 13
Registriert: 25. Dez 2017, 00:06

Re: Mit AWK verschiedene Felder verschiedener Zeilen vergleichen

Beitrag von andreasandy » 28. Dez 2017, 18:54

}-Tux-{ hat geschrieben:
27. Dez 2017, 16:25
Hier mal ein kleiner perl Ein- bzw. Dreizeiler:

Code: Alles auswählen

perl -e 'my %h = map { $_ =~ s/^([^;]+);([^;]+);(.*)\n/$1;$2/r => "$3" } <>; print "$_;$h{$_}\n" for (sort(keys(%h))); print join(";", @$_) . "\n" for grep { !$h{$_->[0]} } map { [s/^([^;]+);([^;]+)$/$2;$1/r, $h{$_}] } sort(keys(%h));' filename
}-Tux-{
Hallo }-Tux-{ ,

Vielen Dank! Ich werde mir das anschauen!

abgdf
Guru
Guru
Beiträge: 3111
Registriert: 13. Apr 2004, 21:15

Re: Mit AWK verschiedene Felder verschiedener Zeilen vergleichen

Beitrag von abgdf » 28. Dez 2017, 19:01

Hübsch häßlich isses ja. Immer, wenn "map()" ins Spiel kommt, steig' ich aus, wird mir dann zu unübersichtlich.

andreasandy
Newbie
Newbie
Beiträge: 13
Registriert: 25. Dez 2017, 00:06

Re: Mit AWK verschiedene Felder verschiedener Zeilen vergleichen

Beitrag von andreasandy » 28. Dez 2017, 19:12

Nun hat das Input-File in Wirklichkeit so eine Form:

PVO;20170301
POU;20170531
SAT;AAA;AAB;10
SAT;AAB;AAA;12
SAT;AAA;FAC;26
SAT;AAA;FAV;15
SAT;DAD;HHZ;89
SAT;AAA;HOI;33
SAT;AAA;MKP;59
SAT;AAA;PPT;45
SAT;AAA;RRR;88
SAT;AAA;TTQ;87
SAT;HHZ;DAD;89
SAT;MKP;AAA;59
ODT;508

Das heißt, es müssen noch immer die ersten 2 Zeilen und eine letzte entfernt werden, und bei den nützlichen Zeilen muss das "SAT;" entfernt werden (das "SAT" steht da immer vor diesen Zeilen).

Mit AWK und mit Hilfe von robi habe ich das so gelöst:

Code: Alles auswählen

BEGIN{
        OFS=";"
        FS=";"
};

{	if ($1 == "SAT")
{
	x[$2,$3]=$4};
};

END{
	for (i in x) 
	{
           	split(i,y,SUBSEP);
           	print y[1],y[2],x[i]
           	if (!((y[2],y[1]) in x)) 
		{
               		print y[2],y[1],x[i]
		}
       	}	
}
Und das funktioniert. Nur verstehe ich nicht, warum keine abschließende geschweifte Klammer zu diesem Ausdruck erforderlich ist, und warum das so funktioniert:

Code: Alles auswählen

{	if ($1 == "SAT")
Wenn ich diese Klammer vor dem "if" entferne, oder noch eine abschließende hinzufüge, funktioniert das nicht mehr.

Außerdem, möchte ich jetzt versuchen das mit dem "SAT" und nicht benötigten Zeilen auch in Python zu lösen.
Aber lässt mich bitte das selbst versuchen :-)

Viele Dank Euch und schöne Grüße,
andreasandy

Benutzeravatar
framp
Moderator
Moderator
Beiträge: 4270
Registriert: 6. Jun 2004, 20:57
Wohnort: bei Stuttgart
Kontaktdaten:

Re: Mit AWK verschiedene Felder verschiedener Zeilen vergleichen

Beitrag von framp » 28. Dez 2017, 19:21

andreasandy hat geschrieben:
28. Dez 2017, 18:48
Ich habe nur vor ein Paar Tagen zum ersten Mal etwas über Go gehört. Steht nicht ganz oben auf meiner Prio-Liste...
Wenn Du an einem Job bei Google interessiert bist solltest Du Deine Prioritäten vielleicht ändern :wink:

Antworten