Menukar jumlah kolom yang tidak terbatas

12

Saya punya file dengan kolom. Lihat di bawah untuk contoh:

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

Saya ingin menukar semua kolom di mana 1 menjadi yang terakhir, yang kedua menjadi yang sebelumnya ... dll.

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

Apakah ada satu liner ( awkatau sed) yang melakukan ini?
Saya tahu seseorang dapat menggunakan awkketika hanya ada beberapa kolom, tetapi saya ingin dapat melakukan ini pada file dengan ribuan kolom.

tacmelakukan ini dengan sempurna untuk baris.
Saya kira saya sedang mencari yang setara untuk kolom.

rev tidak berfungsi untuk saya, karena juga menukar konten di kolom.

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

Jawaban:

15
awk '{for(i=NF;i>0;i--)printf "%s ",$i;print ""}' file
buru-buru
sumber
Saya melakukan kerja terlalu keras untuk tugas yang begitu sederhana. Selalu lebih sederhana lebih baik. +1
Birei
10

Anda bisa melakukannya dengan skrip python kecil:

#!/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))
jmp
sumber
7

Jika Anda tidak keberatan dengan python maka one-liner ini akan membalik urutan kolom yang dipisahkan spasi di setiap baris:

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$ 

Di atas juga berfungsi dengan 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$ 
Paddy3118
sumber
Metode ini adalah yang tercepat dari semua jawaban yang telah saya uji.
Peter.O
4

Salah satu cara menggunakan awk .

Isi dari 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

Jalankan awkperintah berikut :

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

Dengan hasil sebagai berikut:

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
Birei
sumber
3

Ini lambat, tetapi memang memiliki satu fitur penukaran. Ini mempertahankan lebar pemisah bidang, ketika mereka lebih lebar dari satu karakter. FWIW: Jika Anda menjalankan skrip ini dua kali, hasilnya identik dengan aslinya.

Ini skripnya.

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"

Berikut adalah beberapa perbandingan waktu. File tes berisi 1 baris.

                      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
Peter.O
sumber
3

Anda dapat menggunakan tacAnda hanya perlu mengubah input sebelum dan sesudah. Ini dapat dilakukan dengan kalkulator spreadsheet scdan sahabat karibnya psc:

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

Seperti yang terlihat di sini .

Ini bekerja paling baik ketika semua kolom diisi.

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 B C D E F G H I  J  K  L

sampah

  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

Edit

Seperti dicatat oleh PeterO sc memiliki batas keras 702 kolom, sehingga itu adalah ukuran maksimum yang didukung oleh metode ini.

Thor
sumber
1
Ini mengubah angka menjadi floating point (untuk saya) misalnya. 1-> 1.00. Juga, saya mendapatkan kesalahan untuk garis lebih dari 702 bidang. Tampaknya berhubungan dengan batas numerik 32.768 ... tapi ini cukup cepat, asis.
Peter.O
Saya tidak melihat konversi floating point, tetapi menambahkan -Ske pscperintah harus menginterpretasikan segala sesuatu sebagai string. Sehubungan dengan batas kolom 702, itu adalah batas yang sulit karena hanya kolom A sampai ZZ yang didukung (26 + 26 * 26), saya akan menambahkan komentar tentang itu.
Thor
1
Sebenarnya, masalah floating point ok. Saya melihat lebih jauh ke dalamnya, dan saya menemukan bahwa saya tidak harus memeriksa hasil karena saya bergegas keluar pintu .. Poin mengambang hanya terjadi setelah mencapai batas 702 ... Itu lebih cepat daripada jawaban python untuk 1 baris dari 702 bidang, tetapi untuk 100 baris itu menjadi paling lambat dari semua metode yang diberikan :( .. Itu harus memiliki waktu start-up yang lebih pendek daripada python.
Peter.O
3

Saluran pipa ini lebih cepat daripada jawaban tercepat lainnya oleh faktor yang signifikan (lihat hasil). Ini menggunakan trdan tac. Itu perlu menggunakan 2 ASCII byte (\ x00- \ x7F) yang tidak ada dalam data Anda.

\x00 biasanya merupakan pilihan yang baik \x01 , tetapi Anda dapat menggunakan byte ASCII apa pun yang tidak ada dalam data.

Dalam contoh ini, SPACE dan TAB sebagai karakter pembatas. Pembatas bisa multi-byte atau tunggal. Pembatas output adalah ruang tunggal.

Ini perintahnya. Nama file menunjukkan numberof fields_xnumber of lines

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

Jika Anda ingin / perlu memeriksa byte yang tidak digunakan, Anda dapat memeriksa terlebih dahulu dengan awkskrip opsional ini . Waktu keseluruhan, bahkan ketika menjalankan skrip opsional ini, masih jauh lebih cepat daripada metod lainnya (sejauh ini :) .. Berikut adalah skrip pra-pemrosesan.

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

Ini skrip awk: 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}}}

Set waktu kedua, untuk skrip ini, termasuk char-ascii-not-in-streamwaktu.

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

##############################################
Peter.O
sumber
0

Anda juga dapat melakukannya tanpa mencetak f :

awk 'BEGIN{ORS=""} {for(k=NF;k>0;--k) {print $k; if (k==1) print "\n"; else print " "}} ' file
P. D
sumber