Tauschen Sie eine unbegrenzte Anzahl von Spalten aus


12

Ich habe eine Datei mit Spalten. Unten finden Sie ein Beispiel:

a b c ... z  
1 2 3 ... 26

Ich möchte alle Spalten tauschen, in denen die erste zur letzten wird, die zweite zur vorletzten ... etc ..

z y x ... a  
26 25 24 ... 1

Gibt es einen Einzeiler ( awkoder sed) der das macht?
Ich weiß, dass man es verwenden kann, awkwenn nur ein paar Spalten vorhanden sind, aber ich möchte dies für Dateien mit Tausenden von Spalten tun können.

tacmacht dies perfekt für Linien.
Ich schätze, ich suche das Äquivalent für Spalten.

rev hat bei mir nicht funktioniert, da es auch den Inhalt in der Spalte vertauscht.


perl -lane 'print join " ", reverse @F'

Antworten:


15
awk '{for(i=NF;i>0;i--)printf "%s ",$i;print ""}' file

Ich habe zu hart für eine so einfache Aufgabe gearbeitet. Immer einfacher ist es besser. +1
Birei

10

Sie könnten es mit einem kleinen Python-Skript tun:

#!/usr/bin/env python

# Swaps order of columns in file, writes result to a file.
# usage: program.py input_file output_file

import sys, os

out = []

for line in open(sys.argv[1], 'r'):
    fields = line.split()
    rev = ' '.join(list(reversed(fields)))
    out.append(rev)

f = open(sys.argv[2], 'w')
f.write(os.linesep.join(out))

7

Wenn Ihnen Python nichts ausmacht, kehrt dieser Einzeiler die Reihenfolge der durch Leerzeichen getrennten Spalten in jeder Zeile um:

paddy$ cat infile.txt 
a b c d e f g h i j k l
1 2 3 4 5 6 7 8 9 10 11 12
a e i o u
paddy$ python3 -c 'with open("infile.txt") as f: print("\n".join(" ".join(line.rstrip().split()[::-1]) for line in f))'
l k j i h g f e d c b a
12 11 10 9 8 7 6 5 4 3 2 1
u o i e a
paddy$ 

Das obige funktioniert auch mit python2.7:

paddy$ python2.7 -c 'with open("infile.txt") as f: print("\n".join(" ".join(line.rstrip().split()[::-1]) for line in f))'
l k j i h g f e d c b a
12 11 10 9 8 7 6 5 4 3 2 1
u o i e a
paddy$ 

Diese Methode ist die schnellste aller Antworten, die ich getestet habe.
Peter.O

4

Ein Weg mit awk.

Inhalt von infile:

a b c d e f g h i j k l
1 2 3 4 5 6 7 8 9 10 11 12
a e i o u

Führen Sie folgenden awkBefehl aus:

awk '{
    ## Variable 'i' will be incremented from first field, variable 'j'
    ## will be decremented from last field. And their values will be exchanged.
    ## The loop will end when both values cross themselves.
    j = NF; 
    for ( i = 1; i <= NF; i++ ) { 
        if ( j - i < 1 ) { 
            break;
        } 
        temp = $j; 
        $j = $i; 
        $i = temp; 
        j--; 
    }
    print;
}' infile

Mit folgendem Ergebnis:

l k j i h g f e d c b a
12 11 10 9 8 7 6 5 4 3 2 1
u o i e a

3

Dies ist langsam, hat aber eine Einlösungsfunktion. Die Breite von Feldtrennzeichen wird beibehalten, wenn diese breiter als ein einzelnes Zeichen sind. FWIW: Wenn Sie dieses Skript zweimal ausführen, ist das Ergebnis identisch mit dem Original.

Hier ist das Drehbuch.

awk '{ eix = length($0) 
       for( fn=NF; fn>0; fn--) { dix=eix
            while( substr($0,dix,1) ~ /[ \t]/ ) dix--
            printf "%s%s", substr($0,dix+1,eix-dix), $fn
            dix-=length($fn); eix=dix }
       print substr($0,1,dix)
    }' "$file"

Hier einige Zeitvergleiche. Die Testdatei enthielt 1 Zeile.

                      fields           fields     
                      10,0000          10,000,000

user11136 {python} | real  0.029s     real  3.235s
reversible? no     | user  0.032s     user  2.008s
                   | sys   0.000s     sys   1.228s

jmp {python}       | real  0.078s     real  5.045s
reversible? no     | user  0.068s     user  4.268s
                   | sys   0.012s     sys   0.560s

rush {awk}         | real  0.120s     real  10.889s
reversible? no     | user  0.116s     user   8.641s
                   | sys   0.008s     sys    2.252s

petero {awk}       | real  0.319s     real  35.750s
reversible? yes    | user  0.304s     user  33.090s
                   | sys   0.016s     sys    2.660s

3

Sie können verwenden, tacSie müssen nur die Eingabe vorher und nachher transponieren. Dies kann mit dem Tabellenkalkulationsrechner scund seinem Sidekick erfolgenpsc :

< infile psc -S -r | sc -W% - | tac | psc -S -r | sc -W% - > outfile

Wie gesehen hier .

Dies funktioniert am besten, wenn alle Spalten gefüllt sind.

im Ordner

 a b c d e f g h i  j  k  l
 1 2 3 4 5 6 7 8 9 10 11 12
 A B C D E F G H I  J  K  L

outfile

  l  k  j i h g f e d c b a
 12 11 10 9 8 7 6 5 4 3 2 1
  L  K  J I H G F E D C B A

Bearbeiten

Wie von PeterO festgestellt sc, ist die maximale Größe, die von dieser Methode unterstützt wird, auf 702 Spalten beschränkt.


1
Es konvertiert Zahlen in Gleitkommazahlen (für mich), z. 1-> 1.00. Außerdem erhalte ich Fehler für Zeilen, die breiter als 702 Felder sind. Es scheint sich auf ein numerisches Limit von 32768 zu beziehen ... aber es ist ziemlich schnell, wie es scheint.
Peter.O

Ich sehe die Gleitkommakonvertierung nicht, aber das Hinzufügen -Szum pscBefehl sollte alles als Zeichenfolgen interpretieren. In Bezug auf die Spaltenbegrenzung von 702 ist dies eine harte Grenze, da nur Spalten von A bis ZZ unterstützt werden (26 + 26 * 26). Ich werde einen Kommentar dazu hinzufügen.
Thor

1
Tatsächlich wird der Floating - Point - Ausgabe sah ok.I weiter hinein, und ich entdeckte , dass ich nicht Ergebnisse überprüfen , wie ich die Tür eilte aus .. Die Gleitpunkte nur auftreten , nachdem er die Hits 702 Limit ... Es ist schneller als der Python antwortet für 1 Zeile von 702 Feldern, aber für 100 Zeilen wird es die langsamste aller angegebenen Methoden :( .. Es muss eine kürzere Startzeit als Python haben.
Peter.O

3

Diese Pipeline ist um einen signifikanten Faktor schneller als die schnellste andere Antwort (siehe Ergebnisse). Es benutzt trund tac. Es müssen 2 ASCII-Bytes (\ x00- \ x7F) verwendet werden, die in Ihren Daten nicht vorhanden sind.

\x00ist normalerweise eine gute Wahl, \x01aber Sie können jedes ASCII-Byte verwenden, das nicht in den Daten enthalten ist.

In diesem Beispiel sind SPACE und TAB die Begrenzungszeichen. Begrenzer können aus mehreren Bytes oder aus einem Byte bestehen. Das Ausgabebegrenzungszeichen ist ein einzelnes Leerzeichen.

Hier ist der Befehl. Der Dateiname zeigt das numberof fields_xnumber of lines

 <"$file" tr ' \t\n' '\0\0\1' |tr -s '\0' '\n' |tac |tr '\n' ' ' |tr '\1' '\n'

Wenn Sie nach nicht verwendeten Bytes suchen möchten / müssen, können Sie dies vorher mit diesem optionalen awkSkript überprüfen . Die Gesamtzeit, auch wenn dieses optionale Skript ausgeführt wird, ist immer noch erheblich schneller als bei anderen Metoden (bisher :) .. Hier ist das Skript für die Vorverarbeitung.

o=($(<"$file" char-ascii-not-in-stream)); x="${o[0]}"; y="${o[1]}"
<"$file" tr ' \t\n' "$x$x$y" |tr -s "$x" '\n' |tac |tr '\n' ' ' | tr '$y' '\n' >"$file".$user

Dies ist das awk-Skript: char-ascii-not-in-stream

#!/usr/bin/awk -f
{c[$0]} END{for(i=0;i<=127;i++) {if(sprintf("%c", i) in c);else {printf "\\%03o ",i}}}

Die zweite Gruppe von Zeiten für dieses Skript enthält char-ascii-not-in-streamdie Uhrzeit.

Peter.O {tr,tac,tr} ==== file_10_x10000
real    0m0.013s    0m0.015s
user    0m0.020s    0m0.020s
sys     0m0.008s    0m0.012s   

user11136 {python} ===== file_10_x10000
real    0m0.057s
user    0m0.048s
sys     0m0.008s

jmp {python} =========== file_10_x10000
real    0m0.160s
user    0m0.160s
sys     0m0.000s

rush {awk} ============= file_10_x10000
real    0m0.121s
user    0m0.120s
sys     0m0.000s

##############################################

Peter.O {tr,tac,tr} ==== file_1000_x1000
real    0m0.048s    0m0.059s
user    0m0.040s    0m0.040s
sys     0m0.040s    0m0.048s

user11136 {python} ===== file_1000_x1000
real    0m0.158s
user    0m0.136s
sys     0m0.028s

jmp {python} =========== file_1000_x1000
real    0m0.327s
user    0m0.320s
sys     0m0.008s

rush {awk} ============= file_1000_x1000
real    0m0.832s
user    0m0.820s
sys     0m0s012s

##############################################

Peter.O {tr,tac,tr} ==== file_1000000_x50
real    0m5.221s    0m6.458s
user    0m4.208s    0m5.248s
sys     0m2.624s    0m2.396s

user11136 {python} ===== file_1000000_x50
real    0m16.286s
user    0m10.041s
sys     0m5.148s

jmp {python} =========== file_1000000_x50
real    0m22.845s
user    0m20.705s
sys     0m1.140s

rush {awk} ============= file_1000000_x50
real    0m44.793s
user    0m43.583s
sys     0m0.848s

##############################################

0

Sie können es auch ohne Druck machen f :

awk 'BEGIN{ORS=""} {for(k=NF;k>0;--k) {print $k; if (k==1) print "\n"; else print " "}} ' file
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.