จัดเรียงตามค่าฐานสิบหก


14

การใช้ coreutils sortฉันจะจัดเรียงตัวเลขโดยใช้ค่าเลขฐานสิบหก (ฟิลด์) ได้อย่างไร ฉันคาดหวังบางอย่างตามสายของ

sort -k3,3x file_to_sort

แต่ดังกล่าวxไม่ได้อยู่

แก้ไข: ทางออกที่ดีที่สุดที่ฉันได้พบคือ:

{ echo ibase=16; cut -d' ' -f3 file_to_sort; } |
  bc | paste -d: - file_to_sort | sort -t: -k1,1n | cut -d: -f2-

โดยที่cut -d' ' -f3แยกฟิลด์ค้นหา (นี่คือ-k3,3- ซึ่งอาจแตกต่างกันไปแน่นอน) และbcทำการแปลงเป็นทศนิยม (ต้องใช้ hex ตัวพิมพ์ใหญ่โดยไม่มี0xคำนำหน้าตรงกับกรณีของฉัน) จากนั้นฉันเข้าร่วมเรียงลำดับและแยกคอลัมน์


-k3,3? คุณมีเลขฐานสิบหกที่จ้องมองด้วย 0x และมีความยาวเท่ากันหรือไม่ ไม่มีส่วนผสมของตัวอักษรตัวใหญ่ / ตัวเล็ก? ถ้าใช่พวกเขาควรเรียงลำดับที่ถูกต้องเมื่อตีความว่าเป็นสตริง บางทีคุณสามารถแสดงข้อมูลตัวอย่างให้เราดูได้บ้าง

@yeti: น่าเสียดายที่ไม่มี
ฟาน

คำตอบ:


5

ทางออกในperl:

$ perl -anle '
    push @h, [$F[-1],$_];
    END {
        print for map  { $_->[0] }
                  sort { $a->[1] <=> $b->[1] }
                  map  { [$_->[1],hex($_->[0])] } @h;
    }
' file
4 jjk 7
5 hhf 25
2 ukr 9f
3 ezh ae
1 hdh d12

คำอธิบาย

  • ในขณะที่กำลังประมวลผลไฟล์เราสร้างอาร์เรย์ของอาร์เรย์@hแต่ละองค์ประกอบของมันคือการอ้างอิงอาร์เรย์[$F[-1],$_]โดยที่องค์ประกอบแรกคือค่าฐานสิบหกที่จะเปรียบเทียบและองค์ประกอบที่สองคือทั้งบรรทัด

  • ในENDบล็อกเราใช้การแปลง Schwartzian :

    • ด้วยแต่ละองค์ประกอบของ@hสร้างอาร์เรย์ที่ไม่ระบุชื่อมีทั้งบรรทัด ( $_->[1]องค์ประกอบที่สองของแต่ละอ้างอิงอาร์เรย์ใน@h) และค่าฐานสิบหกเพื่อเปรียบเทียบhex($_->[0])]

    • เรียงลำดับข้างบนฐานอาเรย์บนค่าฐานสิบหก $a->[1] <=> $b->[1]

    • รับองค์ประกอบแรกของแต่ละอาร์เรย์อ้างอิงในอาร์เรย์ที่เรียงลำดับmap { $_->[0] } แล้วพิมพ์ผลลัพธ์

ปรับปรุง

ด้วยข้อเสนอแนะของ @Joseph R โดยไม่ใช้การแปลง Schwartzian:

$ perl -anle '
    push @h, [hex($F[-1]),$_];
    END {
        print $_->[1] for
            sort { $a->[0] <=> $b->[0] } @h;
    }
' file

อัปเดต 2

หลังจากอ่านความคิดเห็นของสเตฟานแล้วฉันคิดว่าสิ่งนี้สามารถเรียกdirect:

$ perl -e '
    print sort {hex((split(/\s+/,$a))[-1]) <=> hex((split(/\s+/,$b))[-1])} <>;
' file
4 jjk 7
5 hhf 25
2 ukr 9f
3 ezh ae
1 hdh d12

+1 แต่ทำไมไม่ได้เป็นเพียง: print for sort { hex $a->[-1] <=> hex $b->[-1] } @h? hexผู้ประกอบการก็พอมีราคาแพงแทบจะรับประกัน Schwartzian, ไม่ได้หรือไม่
โจเซฟอาร์.

@JosephR: อาจเป็นไปได้ แต่ Schwartzian นั้นมีความยืดหยุ่นและทำงานได้ในทุกกรณี ฉันคิดว่าเราสามารถมีวิธีแก้ไขปัญหาอื่นโดยการคำนวณค่าฐานสิบหกในขณะที่การประมวลผลจะปรับปรุงคำตอบของฉันในไม่ช้า
cuonglm

ทางออกที่ดี ไม่ทราบว่ารูปแบบนี้มีชื่อ: decor-sort-undecorate ดูความคิดเห็นของฉันด้านบน
ฟาน

@stefan: ดูคำตอบที่อัปเดตของฉัน
cuonglm

@Gnouc: ใช่การอัปเดตครั้งที่ 2 ของคุณมีคุณสมบัติตรงตามที่กำหนดเป็น wrt โดยตรง จินตนาการเริ่มต้นของฉัน
ฟาน

6

ฉันใช้ข้อมูลตัวอย่างนี้:

1 hdh d12
2 ukr 9f
3 ezh ae
4 jjk 7
5 hhf 25

แนวคิดคือการสร้างเวอร์ชันใหม่ของข้อมูลนี้ด้วยฟิลด์การเรียงลำดับในรูปแบบทศนิยม คือawkแปลงมันเป็นการเพิ่มไปยังแต่ละบรรทัดผลลัพธ์จะถูกจัดเรียงและเป็นขั้นตอนสุดท้ายที่ฟิลด์ที่เพิ่มจะถูกลบออก:

awk '{val="0x" $3; sub("^0x0x","0x",val); print strtonum(val),$0 ;}' file | 
  sort -n | 
  sed 's/^[^ ]* //'

ซึ่งผลลัพธ์ในผลลัพธ์นี้:

4 jjk 7
5 hhf 25
2 ukr 9f
3 ezh ae
1 hdh d12

1
ขอบคุณวิธีแก้ปัญหาที่น่าสนใจ ขออภัยที่ฉันไม่ได้โพสต์การแก้ไขของฉันก่อนหน้านี้เป็นไปตามวิธีการที่คล้ายกันโดยใช้ cut + paste ผมก็หวังว่าสำหรับการแก้ปัญหาโดยตรงมากขึ้น แต่ ...
สเตฟาน

@stefan สิ่งที่นับเป็น "โดยตรง"? วิธีการแก้ปัญหาต้องใช้sort?
โจเซฟอาร์.

@Joseph“ สิ่งใดที่นับว่าเป็น“ โดยตรง”?” เป็นคำถามที่ถูกต้อง โดยทั่วไปการแก้ปัญหาทั้งหมดจนถึงตอนนี้ (Hauke's, Gnouc ด้านล่างและของฉัน) ทำสิ่งที่คล้ายกัน: ถอดรหัสค่าฐานสิบหก, แนบผลลัพธ์ไปที่บรรทัด, เรียงลำดับตามและลบออก ฉันกำลังมองหาบางอย่างที่ไม่ได้ใช้รูปแบบการตกแต่งแบบเรียงซ้อน โซลูชันทั้งสองนั้นเหนือกว่าของฉันในการทำงานที่เป็นท่อ ฉันเลือกอันนี้เพราะฉันเองค่อนข้างใช้ awk (ค้อนเล็ก) กว่า Perl สำหรับงานประเภทนี้
ฟาน

ฉันย้ายคำตอบของฉันไปที่ # 3 ด้านล่างเนื่องจากการอัปเดตครั้งที่สองของ Gnouc
ฟาน

1

อินพุต

$ cat /tmp/input
0x45 aaa 333
0x50 dd 33
0x4 bbbb 444
0x456 cc 22
0x5 eee 1111

เรียงลำดับหนึ่งซับ

$ gawk  --non-decimal-data '{ dec = sprintf("%d", $1); print dec " "  $0 }' /tmp/input | sort -n -k 1 | cut -f2- -d' '
0x4 bbbb 444
0x5 eee 1111
0x45 aaa 333
0x50 dd 33
0x456 cc 22

เรียงลำดับขั้นตอน

ขั้นตอนที่ 1: เพิ่มคอลัมน์แรกใหม่ด้วยการแสดงทศนิยมของตัวเลขฐานสิบหก

$ gawk  --non-decimal-data '{ dec = sprintf("%d", $1); print dec " "  $0 }' /tmp/input 
69 0x45 aaa 333
80 0x50 dd 33
4 0x4 bbbb 444
1110 0x456 cc 22
5 0x5 eee 1111

ขั้นตอนที่ 2: เรียงลำดับบรรทัดตัวเลขในฟิลด์แรก

$ gawk  --non-decimal-data '{ dec = sprintf("%d", $1); print dec " "  $0 }' /tmp/input | sort -n -k 1
4 0x4 bbbb 444
5 0x5 eee 1111
69 0x45 aaa 333
80 0x50 dd 33
1110 0x456 cc 22

ขั้นตอนที่ 3: ลบคอลัมน์แรก

$ gawk  --non-decimal-data '{ dec = sprintf("%d", $1); print dec " "  $0 }' /tmp/input | sort -n -k 1 | cut -f2- -d' '
0x4 bbbb 444
0x5 eee 1111
0x45 aaa 333
0x50 dd 33
0x456 cc 22

0

ดัดแปลงมาจาก: http://www.unix.com/302548935-post6.html?s=b4b6b3ed50b6831717f6429113302ad6

: ไฟล์การเรียงลำดับตาม:

6F993B
954B29
A23F2F
BFA91D
C68C15
8F322F
5A6D40
6D512C
9D9D63
B4B823
A0641C
A79716
A18518

คำสั่ง:

awk '{printf("%050s\t%s\n", toupper($0), $0)}' file-to-sort | LC_COLLATE=C sort -k1,1 | cut -f2

เอาท์พุท:

C68C15
BFA91D
B4B823
A79716
A23F2F
A18518
A0641C
9D9D63
954B29
8F322F
6F993B
6D512C
5A6D40

- ที่ใดที่ toupper ($ 0) "อัพเกรด" ตัวอักษรพิมพ์เล็กดังนั้นพวกเขาจะเรียงลำดับแรก (ไม่แน่ใจว่าจำเป็นหรือไม่?)

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.