Menyortir blok garis

12

Saya memiliki file yang berisi 4n baris. Berikut adalah kutipan darinya yang berisi 8 baris

6115 8.88443
6116 6.61875
6118 16.5949
6117 19.4129
6116 6.619 
6117 16.5979 
6118 19.4111
6115 8.88433  

Yang ingin saya lakukan adalah mengurutkan blok, di mana setiap blok terdiri dari 4 baris berdasarkan kolom pertama. Output untuk kutipan harus terlihat seperti yang ditunjukkan di bawah ini.

6115 8.88443
6116 6.61875
6117 19.4129
6118 16.5949
6115 8.88433 
6116 6.619 
6117 16.5979 
6118 19.4111 
Meenakshi
sumber

Jawaban:

16

Salah satu opsi adalah menggunakan untuk menambahkan awalan nomor seri awal setiap baris N (N = 4 dalam kasus Anda). Kemudian masukkan awalan sebagai kolom penyortiran utama sort.

Contoh dengan N = 4:

awk '{print int((NR-1)/4), $0}' file.txt | sort -n -k1,1 -k2,2 | cut -f2- -d' '
iruvar
sumber
7

Jika ini salah dan Anda tidak ingin belajar python, perl atau awk, Anda bisa menggunakan perintah splitdan dasar sort.

Pertama-tama pisahkan file dalam 4 baris potongan dengan -l opsi:

split -a 6 -l 4 input_file my_prefix_
for fn in my_prefix_*; do
    sort -n -o $fn $fn
done
cat my_prefix_* > output_file
rm my_prefix_*

The sort -nmacam oleh nilai numerik dari kolom pertama (999 sebelum 1234). -a 6harus mengurus file dengan 26 ^ 6 * 4 baris. my_prefix_seharusnya menjadi sesuatu yang unik pada direktori tempat Anda bekerja.

Anthon
sumber
3

Anda dapat melakukannya dengan Perl:

perl -nle '
   push @a,$_;
   unless($. % 4){
       print join "\n",sort {$a <=> $b} @a; # Sort @a, and print its contents
       @a = (); # Empty @a to start a new block
   }
' your_file

Bagaimana ini bekerja?

  • -n-> jalankan kode untuk setiap baris input (dan masukkan baris saat ini $_)
  • -l -> tambahkan baris baru ke output apa pun print
  • -e -> jalankan string berikut sebagai kode Perl
  • Setiap baris ditambahkan ke array @a.
  • $.memegang nomor baris saat ini dan kecuali nomor itu tidak kongruen dengan nol modulo 4, maka kami tetap bekerja. Jika adalah kongruen dengan nol modulo 4, kita telah mencapai garis yang jumlahnya merupakan kelipatan dari 4 (akhir blok), dalam hal ini, kita semacam entri dalam @adi urutan menaik numerik dan mencetak entri dalam array diurutkan bergabung dengan baris baru ke output standar.
Joseph R.
sumber
2

Menggunakan shell seperti Bourne,

while read a ; do                                           # Try reading a line.
    read b ; read c ; read d                                # OK, read 3 more.
    printf '%s\n%s\n%s\n%s\n' "$a" "$b" "$c" "$d" | sort -n # Sort them.
done < data
200_sukses
sumber
2

Berikut adalah beberapa awksolusi "murni" :

Jika indeks selalu sama dengan urutan bilangan bulat (6115-6119), seperti pada data sampel Anda, Anda dapat menggunakan "pintasan" algoritmik:

awk '{a[$1]=$0} !(NR%4){for(i=6115;i<6119;print a[i++]);}'

Ini tidak

  • Tambahkan semua baris ke array a, didistribusikan di posisi indeks 6115-6119
  • Pada setiap baris ke-4 ( !(NR%4)), loop melalui isi array untuk mencetak dalam urutan yang diinginkan.

Jika indeks numerik Anda selalu empat yang sama, tetapi bukan urutan bilangan yang bertambah, Anda harus mengurutkan:

awk '{a[$1]=$0} !(NR%4){asort(a,b); for(i=1;i<5;print b[i++]);}'

Catatan: Ini dengan GNU awk, yang lain mungkin tidak mendukung asort.


Jika setiap blok-of-empat dapat memiliki ID numerik yang berbeda:

awk '{a[$1]=$0} !(NR%4){asort(a); for(i=1;i<5;print a[i++]); delete a}'

Catatan: TIL dari @Gilles menjawab sendiri (+2) penggunaan deleteini bukan (belum) POSIX, tetapi didukung secara universal .


Versi dengan penggunaan ™ yang benar dari delete:

awk '{a[$1]=$0} !(NR%4){asort(a); for(i=1;i<5;delete a[i++]){print a[i]}}'

Versi tanpa hapus, menggunakan lebih banyak memori dan dimensi:

awk '{a[n][$1]=$0} !(NR%4){asort(a[n]); for(i=1;i<5;print a[n][i++]); n++}
Alex Stragies
sumber
1

Anda bisa mendapatkan solusi bersih dengan R. Jika tabel di atas dalam file bernama "table.txt", maka lakukan langkah-langkah berikut. Hasil yang diinginkan akan berada di file "tableout.txt".

> x = read.table("table.txt", col.names=c("a", "b"))
> x
     a        b
1 6115  8.88443
2 6116  6.61875
3 6118 16.59490
4 6117 19.41290
5 6116  6.61900
6 6117 16.59790
7 6118 19.41110
8 6115  8.88433
> x["index"] = c(rep(1, 4), rep(2, 4))
> x
     a        b index
1 6115  8.88443     1
2 6116  6.61875     1
3 6118 16.59490     1
4 6117 19.41290     1
5 6116  6.61900     2
6 6117 16.59790     2
7 6118 19.41110     2
8 6115  8.88433     2     
> xord = x[with(x, order(index, a)), ]
> xord
     a        b index
1 6115  8.88443     1
2 6116  6.61875     1
4 6117 19.41290     1
3 6118 16.59490     1
8 6115  8.88433     2
5 6116  6.61900     2
6 6117 16.59790     2
7 6118 19.41110     2
> write.table(xord[,1:2], "tableout.txt", row.names=FALSE, col.names=FALSE)

Lihat juga Cara mengurutkan dataframe oleh kolom (s) di R .

Faheem Mitha
sumber