GNU จัดเรียงการเรียงที่เสถียรเมื่อเรียงลำดับไม่ทราบลำดับ


18

ฉันมีไฟล์สองคอลัมน์ ไฟล์เรียงตามวิธีที่ฉันต้องการในคอลัมน์ 1 แล้ว ฉันต้องการเรียงลำดับในคอลัมน์ 2 ในแต่ละหมวดหมู่ 1 คอลัมน์ อย่างไรก็ตามsortไม่เข้าใจลำดับการเรียงของคอลัมน์ 1

วิธีปกติ (จากคำถามที่คล้ายกันที่นี่ในสแต็ค) จะเป็น:

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

แต่ฉันไม่สามารถระบุการเรียงลำดับบน k1 ได้เนื่องจากมันเป็นกฎเกณฑ์

อินพุตตัวอย่าง:

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

และเอาท์พุท:

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

คำตอบ:


20

คุณสามารถใช้ awk เพื่อเริ่มเรียงใหม่สำหรับแต่ละบล็อก:

% 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} - เมื่อค่าที่บันทึกแตกต่างกันเรามีบล็อกใหม่ดังนั้นเราจึงปิดใด ๆ ที่เริ่มต้นก่อนหน้านี้ sort
  • {print | "sort -k2,2"}'ไพพ์เอาต์พุตไปที่sortเริ่มต้นหากยังไม่ได้รัน (awk สามารถติดตามคำสั่งที่สตาร์ท)

2
awk เหลือเชื่อจริงๆ ฉันชอบสิ่งนี้มากกว่าที่ฉันคาดไว้ซึ่งเป็นการตกแต่งที่ไม่ได้ตกแต่ง!
Evan Benn

ฉันพยายามเปรียบเทียบความสมบูรณ์แบบของคำตอบนี้กับคำตอบอื่น ๆ แต่ไม่แน่ใจว่าทำไมอันนี้จึงใช้ทรัพยากรมากขึ้น ... ความคิดใด ๆ gist.github.com/EvanTheB/5b64eafb84eeaf51c289295ac06e1b0b
Evan Benn

คุณวิ่งข้ามไปกี่ครั้ง
muru

ฉันไม่ได้หาค่าเฉลี่ย แต่ฉันเห็น runtimes ที่สอดคล้องกันในขณะที่ฉันทำซ้ำและตรวจสอบ
Evan Benn

นี่คือไฟล์ที่คล้ายกันกับสิ่งที่ฉันใช้ถ้าคุณต้องการตรวจสอบ:seq 30 | xargs -L1 bash -cs 'yes $1 | head -1000000 | paste - <(seq 1000000) | shuf' bash
Evan Benn

12

คุณสามารถใช้การแปลง Schwartzian (นี่เป็นวิธีการตกแต่งเรียงลำดับ - undecorate ที่คุณพูดถึงในความคิดเห็น แต่น่าจะมีประสิทธิภาพมากกว่าคำตอบที่ดีของ muru เนื่องจากใช้คำเดียวแทนที่จะใช้หลายคำ) - ใช้เพิ่มคอลัมน์คำนำหน้า การเพิ่มค่าด้วยการเปลี่ยนแปลงค่าในคอลัมน์แรกเรียงลำดับตามคอลัมน์คำนำหน้าตามด้วยคอลัมน์"วินาที" (ซึ่งตำแหน่งลำดับได้เลื่อนไปชั่วคราวเนื่องจากการมีคอลัมน์คำนำหน้า) และสุดท้ายกำจัดคอลัมน์คำนำหน้าsortawk3

awk '{print ($1 in a? c+0: ++c)"\t" $0; a[$1]}' file | sort -k1,1n  -k3,3 | cut -f 2-

ฉันประหลาดใจ แต่คุณถูกต้องนี่เร็วกว่าคำตอบอื่น ๆ ! 3 นาทีเทียบกับ 2 นาทีในไฟล์ 100 ล้านบรรทัดของฉัน (ประมาณ 30 คอลัมน์แรก)
Evan Benn

1
ไม่จำเป็นต้องเก็บอาร์เรย์ของคีย์เฉพาะจากคอลัมน์แรก ฉันคิดว่ามันควรจะเพียงพอที่จะเปรียบเทียบคอลัมน์แรกของบรรทัดปัจจุบันกับคอลัมน์ก่อนหน้า
Kusalananda

บางสิ่งที่ชอบawk -v OFS="\t" '$1 != prev { key++ } { print key, $0; prev = $1 }(ยังไม่ทดลอง)
Kusalananda
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.