กำลังพยายามเรียงลำดับในสองเขตข้อมูลรองจากนั้นก่อน


106

ฉันพยายามเรียงลำดับหลายคอลัมน์ ผลลัพธ์ไม่เป็นไปตามที่คาดไว้

นี่คือข้อมูลของฉัน (people.txt):

Simon Strange 62
Pete Brown 37
Mark Brown 46
Stefan Heinz 52
Tony Bedford 50
John Strange 51
Fred Bloggs 22
James Bedford 21
Emily Bedford 18
Ana Villamor 44
Alice Villamor 50
Francis Chepstow 56

การทำงานต่อไปนี้ถูกต้อง:

bash-3.2$ sort -k2 -k3 <people.txt                                                                                                                    
Emily Bedford 18                                                                                                                                      
James Bedford 21                                                                                                                                      
Tony Bedford 50                                                                                                                                       
Fred Bloggs 22                                                                                                                                        
Pete Brown 37                                                                                                                                         
Mark Brown 46                                                                                                                                         
Francis Chepstow 56                                                                                                                                   
Stefan Heinz 52                                                                                                                                       
John Strange 51                                                                                                                                       
Simon Strange 62                                                                                                                                      
Ana Villamor 44                                                                                                                                       
Alice Villamor 50

แต่สิ่งต่อไปนี้ใช้ไม่ได้ตามที่คาดไว้:

bash-3.2$ sort -k2 -k1 <people.txt                                        
Emily Bedford 18                                                                                                                                      
James Bedford 21                                                                                                                                      
Tony Bedford 50                                                                                                                                       
Fred Bloggs 22                                                                                                                                        
Pete Brown 37                                                                                                                                         
Mark Brown 46                                                                                                                                         
Francis Chepstow 56                                                                                                                                   
Stefan Heinz 52                                                                                                                                       
John Strange 51                                                                                                                                       
Simon Strange 62                                                                                                                                      
Ana Villamor 44                                                                                                                                       
Alice Villamor 50

ฉันพยายามจัดเรียงตามนามสกุลแล้วตามชื่อ แต่คุณจะเห็นว่า Villamors ไม่ได้อยู่ในลำดับที่ถูกต้อง ฉันหวังว่าจะเรียงตามนามสกุลและจากนั้นเมื่อนามสกุลตรงกันเพื่อเรียงตามชื่อ

ดูเหมือนว่ามีบางอย่างเกี่ยวกับวิธีการทำงานนี้ฉันไม่เข้าใจ ฉันสามารถทำสิ่งนี้ได้ด้วยวิธีอื่น (โดยใช้ awk) แต่ฉันต้องการเข้าใจการเรียงลำดับ

ฉันใช้ Bash shell มาตรฐานบน Mac OS X

คำตอบ:


159

ข้อกำหนดสำคัญเช่น-k2หมายถึงการใช้ฟิลด์ทั้งหมดตั้งแต่ 2 ถึงจุดสิ้นสุดของบรรทัดในการพิจารณา ดังนั้นจะจบลงก่อนVillamor 44 Villamor 50เนื่องจากทั้งสองนี้ไม่เท่ากันการเปรียบเทียบครั้งแรกsort -k2 -k1ก็เพียงพอที่จะแยกแยะสองบรรทัดนี้และคีย์การเรียงลำดับที่สอง-k1ไม่ได้ถูกเรียกใช้ หาก Villamors ทั้งสองมีอายุเท่ากัน-k1ก็จะทำให้พวกเขาถูกจัดเรียงตามชื่อ

หากต้องการจัดเรียงตามคอลัมน์เดียวให้ใช้-k2,2เป็นข้อกำหนดของคีย์ นี่หมายถึงการใช้ฟิลด์จาก # 2 ถึง # 2 นั่นคือเฉพาะฟิลด์ที่สอง

sort -k2 -k3 <people.txtซ้ำซ้อน: sort -k2 <people.txtมันเทียบเท่ากับ หากต้องการจัดเรียงตามนามสกุลจากนั้นชื่อแรกตามด้วยอายุให้รันคำสั่งต่อไปนี้:

sort -k2,2 -k1,1 <people.txt

หรือเท่ากันsort -k2,2 -k1 <people.txtเนื่องจากมีเพียงสามฟิลด์เท่านั้นและตัวคั่นเป็นเหมือนกัน ในความเป็นจริงคุณจะได้รับผลกระทบที่เหมือนกันsort -k2,2 <people.txtเพราะsortใช้ทั้งบรรทัดเป็นทางเลือกสุดท้ายเมื่อคีย์ทั้งหมดในชุดย่อยของบรรทัดเหมือนกัน

โปรดทราบว่าตัวคั่นฟิลด์เริ่มต้นคือการเปลี่ยนระหว่างช่องว่างและช่องว่างดังนั้นคีย์จะรวมช่องว่างนำหน้า (ในตัวอย่างของคุณสำหรับบรรทัดแรกคีย์แรกจะเป็น"Emily"แต่คีย์ที่สอง" Bedford"เพิ่ม-bตัวเลือกเพื่อตัดช่องว่างเหล่านั้น:

sort -b -k2,2 -k1,1

นอกจากนี้ยังสามารถทำได้แบบต่อคีย์โดยการเพิ่มbแฟล็กที่ส่วนท้ายของข้อกำหนดคุณลักษณะการเริ่มต้นคีย์:

sort -k2b,2 -k1,1 <people.txt

แต่สิ่งที่ต้องคำนึงถึง: ทันทีที่คุณเพิ่มหนึ่งธงดังกล่าวลงในข้อมูลจำเพาะหลักธงโลก (เช่น-n, -r... ) จะไม่มีผลกับพวกเขาอีกต่อไปดังนั้นจึงเป็นการดีกว่าที่จะหลีกเลี่ยงการผสมธงต่อคีย์และธงโลก


6
คุณตอกมัน ฉันสันนิษฐานว่าเป็นสิ่งที่อันตรายที่ต้องระบุ -k1 หมายถึงใช้ฟิลด์ 1 ซึ่งฟิลด์จะสิ้นสุดที่ตัวคั่นฟิลด์เริ่มต้น (ช่องว่าง) แต่เมื่อคุณชี้ให้เห็นอย่างชัดเจนตัวเลือก k คาดหวังให้คุณระบุจุดเริ่มต้นและจุดหยุดของคีย์ซึ่งอาจเป็นหรือไม่มีฟิลด์เดียวก็ได้ โซลูชันของคุณทำงานได้อย่างสมบูรณ์และที่สำคัญกว่านั้นฉันชัดเจนว่าทำไมถึงเป็นเช่นนั้น ขอบคุณมาก.
แฮร์รี่

นี่คือขนาดใหญ่ แหล่งข้อมูลอื่น ๆ อีกมากมายเกี่ยวกับ KEYDEF พูดคุยเกี่ยวกับ -k1 -k2 โดยไม่เน้นความสำคัญของ COMMA ในรูปแบบเพื่อ จำกัด คอลัมน์ที่จะพิจารณาในแต่ละขั้นตอนการเรียงลำดับ ฉันติดอยู่กับเรื่องนี้หลายชั่วโมงจนกระทั่งพบคำตอบนี้ และหน้าคนสับสนนี่ ไม่ได้อธิบายว่ามีการระบุตำแหน่ง "เริ่มต้นและหยุด" ด้วยเครื่องหมายจุลภาค ขอขอบคุณ!
Jason Rohrer

16

ด้วย GNU sortคุณทำเช่นนี้ไม่แน่ใจเกี่ยวกับ MacOS:

sort -k2,2 -k1 <people.txt

อัปเดตตามความคิดเห็น อ้างจากman sort:

   -k, --key=KEYDEF
          sort via a key; KEYDEF gives location and type

   KEYDEF is F[.C][OPTS][,F[.C][OPTS]] for start and stop position, where
   F is a field number and C a character position in the field; both are
   origin 1, and the stop position defaults to the line's end.

4
คุณช่วยอธิบายสัญลักษณ์ที่แปลกประหลาดนี้ได้ไหม
scai

1
นี่ทำให้ฉันคิดว่าถูกต้องแล้ว - ขอบคุณสำหรับสิ่งนั้น แต่คุณไม่จำเป็นต้องระบุจุดหยุดสำหรับวินาที -k นั่นคือ -k2,2 -k1,1 มิฉะนั้นจุดหยุดจะถูกนำมาเป็นจุดสิ้นสุดของบรรทัด?
แฮร์รี่

@TonyBedford ถูกต้อง แต่การไม่ระบุตำแหน่งหยุดจะไม่เปลี่ยนผลลัพธ์สำหรับอินพุตปัจจุบันของคุณ แต่จะบังคับให้มีความสม่ำเสมอในกรณีที่คุณจะมีหลายบรรทัดที่มีฟิลด์เหมือนกัน 2 และ 1 ดังนั้นฉันต้องการอนุญาตให้รวมล่าสุด-kเท่าที่จะทำได้
จัดการ

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