Trao đổi không giới hạn số lượng cột


12

Tôi có một tập tin với các cột. Xem ví dụ bên dưới:

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

Tôi muốn trao đổi tất cả các cột trong đó cột thứ nhất trở thành cột cuối cùng, cột thứ hai trở thành cột trước cuối ... vv ..

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

Có một lót ( awkhoặc sed) làm điều này?
Tôi biết người ta có thể sử dụng awkkhi chỉ có một vài cột, nhưng tôi muốn có thể làm điều này trên các tệp có hàng ngàn cột.

taclàm điều này hoàn hảo cho các dòng.
Tôi đoán tôi đang tìm kiếm tương đương cho các cột.

rev đã không làm việc cho tôi, vì nó cũng hoán đổi nội dung trong cột.


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

Câu trả lời:


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

Tôi đã làm việc quá sức cho một nhiệm vụ đơn giản như vậy. Luôn luôn đơn giản thì tốt hơn. +1
Birei

10

Bạn có thể làm điều đó với một kịch bản python nhỏ:

#!/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

Nếu bạn không nhớ python thì lớp lót này sẽ đảo ngược thứ tự các cột được phân tách không gian trong mỗi dòng:

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$ 

Trên đây cũng hoạt động với 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$ 

Phương pháp này là nhanh nhất trong tất cả các câu trả lời tôi đã thử nghiệm.
Peter.O

4

Một cách sử dụng awk.

Nội dung của 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

Chạy awklệnh sau :

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

Với kết quả như sau:

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

Điều này là chậm, nhưng nó có một tính năng đổi thưởng. Nó duy trì độ rộng của dải phân cách trường, khi chúng rộng hơn một ký tự. FWIW: Nếu bạn chạy tập lệnh này hai lần, kết quả giống hệt với bản gốc.

Đây là kịch bản.

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"

Dưới đây là một số so sánh thời gian. Các tập tin thử nghiệm có 1 dòng.

                      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

Bạn có thể sử dụng tacbạn chỉ cần hoán chuyển đầu vào trước và sau. Điều này có thể được thực hiện với máy tính bảng tính scvà phụ của nó psc:

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

Như đã thấy ở đây .

Điều này hoạt động tốt nhất khi tất cả các cột được lấp đầy.

trong tập tin

 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

sẵn sàng

  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

Biên tập

Theo ghi nhận của PeterO sc có giới hạn cứng là 702 cột, do đó, đó là kích thước tối đa được hỗ trợ bởi phương pháp này.


1
Nó chuyển đổi số thành các dấu chấm động (đối với tôi), vd. 1-> 1.00. Ngoài ra, tôi gặp lỗi cho các dòng rộng hơn 702 trường. Nó dường như có liên quan đến giới hạn số 32768 ... nhưng nó khá nhanh, asis.
Peter.O

Tôi không thấy chuyển đổi dấu phẩy động, nhưng thêm -Svào psclệnh sẽ diễn giải mọi thứ dưới dạng chuỗi. Liên quan đến giới hạn cột 702, đó là giới hạn cứng vì chỉ hỗ trợ các cột từ A đến ZZ (26 + 26 * 26), tôi sẽ thêm nhận xét về điều đó.
Thor

1
Trên thực tế, vấn đề về dấu phẩy động là ok. Tôi đã xem xét thêm và tôi phát hiện ra rằng tôi không nên kiểm tra kết quả khi tôi vội vã ra khỏi cửa .. Các điểm nổi chỉ xảy ra sau khi nó đạt đến giới hạn 702 ... Nó nhanh hơn câu trả lời của python cho 1 dòng 702 trường, nhưng với 100 dòng thì nó trở thành chậm nhất trong tất cả các phương thức đã cho :( .. Nó phải có thời gian khởi động ngắn hơn python.
Peter.O

3

Đường ống này nhanh hơn câu trả lời nhanh nhất khác bởi một yếu tố quan trọng (xem kết quả). Nó sử dụng trtac. Nó không cần sử dụng 2 byte ASCII (\ x00- \ x7F) không tồn tại trong dữ liệu của bạn.

\x00thường là một lựa chọn tốt \x01, nhưng bạn có thể sử dụng bất kỳ byte ASCII nào không có trong dữ liệu.

Trong ví dụ này, SPACE và TAB là các ký tự phân cách. Dấu phân cách có thể là nhiều byte hoặc đơn. Dấu phân cách đầu ra là một khoảng trắng.

Đây là lệnh. Tên tệp hiển thị numberof fields_xnumber of lines

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

Nếu bạn muốn / cần kiểm tra các byte không sử dụng, bạn có thể kiểm tra trước với awktập lệnh tùy chọn này . Tổng thời gian, ngay cả khi chạy tập lệnh tùy chọn này, vẫn nhanh hơn đáng kể so với các metod khác (cho đến nay :) .. Đây là tập lệnh tiền xử lý.

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

Đây là kịch bản 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}}}

Nhóm lần thứ hai, đối với tập lệnh này, bao gồm char-ascii-not-in-streamthời gian.

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

Bạn cũng có thể làm điều đó mà không cần in f :

awk 'BEGIN{ORS=""} {for(k=NF;k>0;--k) {print $k; if (k==1) print "\n"; else print " "}} ' file
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.