GNU sortir sortir stabil bila sortir tidak tahu urutan sortir

18

Saya memiliki file dua kolom; file disortir seperti yang saya inginkan pada kolom 1 sudah. Saya ingin mengurutkan pada kolom 2, dalam setiap kategori kolom 1. Namun, sorttidak mengerti urutan pengurutan kolom 1.

Cara biasa (dari pertanyaan serupa di stack) adalah sebagai berikut:

sort --stable -k1,1 -k2,2n

Tapi saya tidak bisa menentukan jenisnya pada k1, karena ini arbitrer.

Contoh input:

C 2
C 1
A 2
A 1
B 2 
B 1

dan output:

C 1
C 2
A 1
A 2
B 1 
B 2
Evan Benn
sumber

Jawaban:

20

Anda bisa menggunakan awk untuk memulai pengurutan baru untuk setiap blok:

% awk -v cmd="sort -k2,2" '$1 != prev {close(cmd); prev=$1} {print | cmd}' foo
C 1
C 2
A 1
A 2
B 1
B 2
  • $1 != prev {close(cmd); prev=$1} - ketika nilai yang disimpan berbeda, kami memiliki blok baru, jadi kami menutup semua yang dimulai sebelumnya sort
  • {print | "sort -k2,2"}'menyalurkan output ke sort, mulai jika belum berjalan (awk dapat melacak perintah yang dimulai)
muru
sumber
2
awk benar-benar luar biasa. Saya suka ini lebih dari apa yang saya harapkan, yang merupakan awk menghias-semacam-undecorate!
Evan Benn
Saya mencoba membandingkan perf ini vs jawaban yang lain, tidak yakin mengapa yang ini menggunakan lebih banyak sumber daya ... Ada ide? gist.github.com/EvanTheB/5b64eafb84eeaf51c289295ac06e1b0b
Evan Benn
Berapa banyak berjalan yang Anda rata-rata melintas?
muru
Saya tidak melakukan rata-rata, tetapi saya melihat runtimes yang konsisten ketika saya ulangi dan selidiki.
Evan Benn
Berikut adalah file yang mirip dengan apa yang saya gunakan jika Anda ingin menyelidiki:seq 30 | xargs -L1 bash -cs 'yes $1 | head -1000000 | paste - <(seq 1000000) | shuf' bash
Evan Benn
12

Anda dapat menggunakan transformasi Schwartzian (ini pada dasarnya adalah pendekatan menghias-sort-tidak-dekorasi yang Anda singgung dalam komentar, tetapi kemungkinan lebih berkinerja daripada jawaban baik muru karena menggunakan doa tunggal sebagai lawan dari banyak) - menggunakan tambahkan kolom awalan yang kenaikan dengan perubahan nilai di kolom pertama, urutkan berdasarkan kolom awalan diikuti oleh kolom "kedua" (yang posisi ordinalnya telah sementara bergeser karena adanya kolom awalan), dan akhirnya singkirkan kolom awalansortawk3

awk '{print ($1 in a? c+0: ++c)"\t" $0; a[$1]}' file | sort -k1,1n  -k3,3 | cut -f 2-
iruvar
sumber
Saya terkejut, tetapi Anda benar, ini lebih cepat daripada jawaban yang lain! 3 menit vs 2 menit pada file 100 juta baris saya (~ 30 kolom pertama uniq).
Evan Benn
1
Tidak perlu menyimpan larik kunci unik dari kolom pertama. Saya pikir itu harus cukup untuk membandingkan kolom pertama baris saat ini dengan yang sebelumnya.
Kusalananda
Sesuatu seperti awk -v OFS="\t" '$1 != prev { key++ } { print key, $0; prev = $1 }(belum diuji).
Kusalananda