Wie kann ich zwischen zwei Matrizen filtern?


7

Datei1:

91  23  56  44  87  77
99  34  56  22  22  95
41  88  26  79  60  27
95  55  66  69  92  25

Datei2:

pass fail pass pass pass fail
pass fail pass fail fail pass
pass pass fail pass pass fail
pass pass fail pass pass fail

Da ich die Gesamtzahl der Fehlschläge für jede Zeile zusammenfassen möchte, ist hier die erwartete Ausgabe.

Ausgabe:

100
78
53
91

Ich möchte fragen, wie ich die Filterung für Datei1 basierend auf dem Wort "Fehler" in Datei2 durchführen kann, um die Summe der Fehlermarkierungen zu erhalten.


Was produziert diese beiden Dateien und kann das Programm das nicht?
Kusalananda

Antworten:


4

Ich glaube nicht, dass Sie einen ENDAbschnitt brauchen :

awk '
NR == FNR       {for (i=1; i<=NF; i++) F[i,NR] = $i
                 next
                }
                {T = 0
                 for (i=1; i<=NF; i++) T += ($i=="fail")?F[i,FNR]:0
                 print T
                }
' file[12]
100
78
53
91

Sie haben Recht, END-Abschnitt ist redundant, +1.
Jimmyij

10

Ich würde für eine solche Aufgabe eine Matrixsprache verwenden, z. B. GNU Octave.

Angenommen, Sie haben die Pass / Fail-Datei in numerische Werte konvertiert, z.

sed 's/pass/1/g; s/fail/0/g' passfail > passfail.nums

Sie können jetzt Folgendes tun:

marks    = dlmread('marks');
passfail = dlmread('passfail.nums');

for i = 1:size(marks)(1)
  sum(marks(i,:)(passfail(i,:) == 0))
end

Ausgabe:

ans =  100
ans =  78
ans =  53
ans =  91

7

Während ich denke, dass die Verwendung awkfür die Portabilität gut ist, scheinen andere Sprachen für diese Aufgabe einfacher zu schreiben und zu lesen. GNU Octave wurde erwähnt, ist jedoch auf den meisten Computern nicht vorinstalliert. Auf den meisten Systemen ist jedoch eine Python-Version vorinstalliert. Hier ist eine Python-Version:

for marks, decisions in zip(open('file1').readlines(), open('file2').readlines()):
    row_score = 0
    for mark, decision in zip(marks.split(), decisions.split()):
        if decision == 'fail':
            row_score += int(mark)
    print(row_score)

Dies gibt die erwarteten Ausgaben zurück.


6

Hier ist mein awkAnsatz:

awk 'NR==FNR{for(i=1;i<=NF;i++) a[NR"-"i]=$i; next} \
            {for(j=1;j<=NF;j++) if($j=="fail") b[FNR]+=a[FNR"-"j]} \
         END{for(k in b) print b[k]}' file1 file2

Awk unterstützt keine zweidimensionalen Arrays, daher haben wir diese gekocht, indem wir zwei Zahlen (Zeile und Feld) im selben Array-Index kombiniert haben. Die Ausgabe ist:

100
78
53
91

4
awk '
  BEGIN{ pf=ARGV[2]; ARGV[2]="" }
  { getline l <pf; split(l, a); n=0;
    for(i=1;i<=NF;i++) if(a[i]=="fail") n+=$i;
    print n }
' file1 file2
100
78
53
91

Genau wie die Python-Version von @ Maxim, aber im Gegensatz zu allen anderen Antworten werden die beiden Dateien Zeile für Zeile parallel verarbeitet, anstatt eine davon vollständig in den Speicher zu laden.


2

Ich denke, die Verwendung eines AwkSkripts würde es etwas einfacher machen, diese Anforderung zu lösen. Mach so etwas wie unten. Ich denke, es ist etwas langsamer als jetzt

#!/usr/bin/awk -f


FNR == NR {
    for(i=1;i<=NF;i++)
        if ( $i == "fail")
            idxArray[FNR] = (idxArray[FNR]) ? (idxArray[FNR]" "i):(i)
        next
}{
    delete Array
    delete Line
    i=""
    j=""
    sum=""
    n=split(idxArray[FNR],Array," ")
    l=split($0,Line," ")
    for (i=1;i<=n;i++)
        for (j=1;j<=l;j++)
            if (Array[i] == j )
                sum += Line[j]
    print sum
}

und führen Sie das Skript als aus

awk -f script.awk file2 file1

0

Einzeiler:

paste file[12] | awk '{T=0; for (i=1; i<=NF/2; i++) T += ($(i+NF/2)=="fail")?$i:0; print T}'
100
78
53
91
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.