เรียงลำดับแฮชตามคีย์แล้วส่งคืนแฮชใน Ruby


258

นี่เป็นวิธีที่ดีที่สุดในการเรียงลำดับแฮชและส่งคืนวัตถุแฮช (แทนที่จะเป็นอาร์เรย์) หรือไม่:

h = {"a"=>1, "c"=>3, "b"=>2, "d"=>4}
# => {"a"=>1, "c"=>3, "b"=>2, "d"=>4}

Hash[h.sort]
# => {"a"=>1, "b"=>2, "c"=>3, "d"=>4}

9
ฉันไม่แน่ใจว่ามีประโยชน์มากเพียงใดในการจัดเรียงแฮชยกเว้นว่าคุณกำลังใช้eachหรือวนeach_pairซ้ำ ถึงอย่างนั้นฉันก็ยังอาจคว้ากุญแจเรียงลำดับแล้วทำซ้ำพวกเขาคว้าค่าตามที่ต้องการ เพื่อให้แน่ใจว่ารหัสจะทำงานอย่างถูกต้องในทับทิมเก่า
คนดีบุก

ทำให้รู้สึกใน ruby ​​1.9 เช่นกัน ฉันมีชุดของการนัดหมายที่จัดกลุ่มตามวันที่ (เป็นกุญแจ) ที่มาจาก db และฉันเรียงลำดับด้วยทับทิมด้วยตนเอง เช่น. {"2012-09-22": [... ], "2012-09-30": [... ], "2012-10-12": [... ]}
Adit Saxena

ใช่ฉันพบแฮชของคุณ [h.sort] ประมวลผลที่มีประสิทธิภาพมากกว่าการเรียงลำดับคีย์จากนั้นเข้าถึงแฮชรางคีย์ที่เรียงลำดับอีกครั้ง
Douglas


3
คุณมีเวลาสองสามปีที่จะคิดเกี่ยวกับวิธีแก้ปัญหาของคุณคุณพร้อมที่จะรับคำตอบหรือไม่? ;-)
Mark Thomas

คำตอบ:


219

ใน Ruby 2.1 มันง่ายมาก:

h.sort.to_h

@zachaysan แต่ใช้งานได้: h.sort{|a,z|a<=>z}.to_h(ทดสอบ 2.1.10, 2.3.3)
whitehat101

@ whitehat101 คุณพูดถูก ฉันมีข้อผิดพลาด ( aเป็นอาร์เรย์ไม่ใช่แค่กุญแจ) ฉันลบความคิดเห็นแล้ว
zachaysan

ในกรณีที่คนอื่นจะมองหาวิธีการเรียงลำดับอาร์เรย์ของ hashes ที่นี้จะทำเคล็ดลับ (ที่ h คืออาร์เรย์) h.map(&:sort).map(&:to_h)A:
JM Janzen

82

หมายเหตุ: Ruby> = 1.9.2 มีแฮชที่เก็บรักษาคำสั่ง: รหัสคำสั่งที่ใส่จะเป็นลำดับที่ระบุ ด้านล่างนี้ใช้กับเวอร์ชันเก่าหรือรหัสที่เข้ากันได้ย้อนหลัง

ไม่มีแนวคิดของแฮชที่เรียงลำดับ ดังนั้นไม่สิ่งที่คุณทำไม่ถูกต้อง

หากคุณต้องการให้เรียงลำดับเพื่อแสดงคืนสตริง:

"{" + h.sort.map{|k,v| "#{k.inspect}=>#{v.inspect}"}.join(", ") + "}"

หรือถ้าคุณต้องการปุ่มตามลำดับ:

h.keys.sort

หรือถ้าคุณต้องการเข้าถึงองค์ประกอบตามลำดับ:

h.sort.map do |key,value|
  # keys will arrive in order to this block, with their associated value.
end

แต่โดยสรุปแล้วมันไม่มีเหตุผลที่จะพูดถึงแฮชที่เรียงลำดับแล้ว จากเอกสาร "ลำดับที่คุณใช้แฮชโดยคีย์หรือค่าอาจดูไม่ได้โดยพลการและโดยทั่วไปจะไม่อยู่ในลำดับการแทรก" ดังนั้นการแทรกกุญแจตามลำดับเฉพาะลงในแฮชจะไม่ช่วย


สิ่งนี้ถูกต้อง ฉันขอแนะนำให้ใช้อัญมณี RBtree เพื่อรับฟังก์ชั่นชุดสั่งในทับทิม
Aaron Scruggs

26
คำสั่งการแทรกแฮชเริ่มต้น 1.9.2 จะถูกเก็บไว้ ดูredmine.ruby-lang.org/issues/show/994
David

4
"การเริ่มต้นคำสั่งการแทรกแฮช 1.9.2 จะถูกเก็บรักษาไว้" และมันก็น่ารัก
Tin Man

2
ความคิดเห็นแรกของฉันอีกครั้ง (รู้สึกตลก): ยกตัวอย่างเช่นการใช้แฮชในการสั่งซื้อจะเงียบและไม่คาดคิดสำหรับรุ่นทับทิมที่เก่ากว่า 1.9.2
Jo Liss

5
คำตอบนี้มีประมาณ 20 + 1 โดยไม่ตอบไม่แม้แต่หนึ่งในสองส่วนของคำถาม OP "1) นั่น (ตัวอย่าง OP) เป็นวิธีที่ดีที่สุดในการเรียงแฮช 2) และส่งคืนวัตถุแฮช" หรือไม่ ฉันไม่ได้ +1 ความอิจฉา :) หลังจากนั้นก็อ่านคำตอบที่ฉันยังเหลืออยู่กับคำถามดั้งเดิม นอกจากนี้หากประเด็นก็คือว่าไม่มีสิ่งดังกล่าวเป็นลักษณะกัญชาเรียงลำดับในการแสดงความคิดเห็นสำหรับคำตอบที่เลือกได้กับคำถามนี้stackoverflow.com/questions/489139/...
jj_

64

sort_byผมเคยใช้เสมอ คุณจำเป็นต้องตัด#sort_byเอาท์พุทด้วยHash[]เพื่อให้มันส่งออกแฮมิฉะนั้นจะส่งออกอาร์เรย์ของอาร์เรย์ อีกวิธีหนึ่งเพื่อให้บรรลุนี้คุณสามารถเรียกใช้#to_hวิธีการในอาร์เรย์ของ tuples เพื่อแปลงให้เป็นk=>vโครงสร้าง (แฮ)

hsh ={"a" => 1000, "b" => 10, "c" => 200000}
Hash[hsh.sort_by{|k,v| v}] #or hsh.sort_by{|k,v| v}.to_h

มีคำถามคล้ายกันใน " วิธีจัดเรียง Ruby Hash ตามค่าตัวเลข "


8
การใช้sort_byแฮชจะส่งคืนอาร์เรย์ คุณจะต้องแมปแฮชอีกครั้ง Hash[hsh.sort_by{|k,v| v}]
stevenspiel

1
ใช่คลาส enumerator ตีความแฮชเป็นอาร์เรย์ฉันคิดว่า
boulder_ruby

3
hsh.sort_by(&:last).to_h => {"b"=>10, "a"=>1000, "c"=>200000}ขวาจัดเรียงอยู่บนค่า:
Cary Swoveland

1
โปรดทราบว่าการโทรto_hสามารถใช้ได้กับ Ruby 2.1.0+ เท่านั้น
Phrogz

1
มีการพิมพ์ผิดในความคิดเห็นการแก้ไข:sort_by{|k,v| v}.to_h)
กระวนกระวายใจ

13

ไม่มันไม่ใช่ (Ruby 1.9.x)

require 'benchmark'

h = {"a"=>1, "c"=>3, "b"=>2, "d"=>4}
many = 100_000

Benchmark.bm do |b|
  GC.start

  b.report("hash sort") do
    many.times do
      Hash[h.sort]
    end
  end

  GC.start

  b.report("keys sort") do
    many.times do
      nh = {}
      h.keys.sort.each do |k|
        nh[k] = h[k]
      end
    end
  end
end

       user     system      total        real
hash sort  0.400000   0.000000   0.400000 (  0.405588)
keys sort  0.250000   0.010000   0.260000 (  0.260303)

สำหรับความแตกต่างของแฮ็ชขนาดใหญ่จะเพิ่มขึ้นเป็น 10 เท่าและมากกว่า


12

คุณให้คำตอบที่ดีที่สุดสำหรับตัวคุณเองใน OP: Hash[h.sort]หากคุณต้องการความเป็นไปได้มากขึ้นนี่คือการดัดแปลงแฮชแบบดั้งเดิมเพื่อให้เรียงลำดับ:

h.keys.sort.each { |k| h[k] = h.delete k }

1
สำหรับคนที่อยากรู้อยากเห็นสิ่งนี้จะทำงานเร็วกว่า "การเรียงคีย์" เล็กน้อยในstackoverflow.com/a/17331221/737303บน Ruby 1.9.3
ไนโตรเจน

9

เรียงลำดับแฮชตามคีย์แล้วส่งคืนแฮชใน Ruby

ด้วยdestructuringและ Hash # sort

hash.sort { |(ak, _), (bk, _)| ak <=> bk }.to_h

นับ # sort_by

hash.sort_by { |k, v| k }.to_h

Hash # sort พร้อมพฤติกรรมเริ่มต้น

h = { "b" => 2, "c" => 1, "a" => 3  }
h.sort         # e.g. ["a", 20] <=> ["b", 30]
hash.sort.to_h #=> { "a" => 3, "b" => 2, "c" => 1 }

หมายเหตุ: <Ruby 2.1

array = [["key", "value"]] 
hash  = Hash[array]
hash #=> {"key"=>"value"}

หมายเหตุ:> Ruby 2.1

[["key", "value"]].to_h #=> {"key"=>"value"}

1
ถ้าไม่ได้ใช้vคุณควรใส่เครื่องหมายขีดล่างไว้hash.sort_by { |k, _v| k }.to_h
silva96

6

ActiveSupport :: OrderedHashเป็นอีกตัวเลือกหนึ่งหากคุณไม่ต้องการใช้ ruby ​​1.9.2 หรือแก้ไขปัญหาของคุณเอง


ลิงก์ใช้งานไม่ได้
Snake Sanders

3
ฉันแก้ไขลิงก์ให้ชี้ไปที่ Google ในกรณีที่นักประวัติศาสตร์บางคนต้องการค้นคว้าว่าเรื่องนี้เกิดขึ้นได้อย่างไรในอดีต แต่ใครก็ตามที่เข้ามาในตอนนี้ควรใช้ทับทิมเวอร์ชันใหม่กว่านี้
eremite

0
@ordered = {}
@unordered.keys.sort.each do |key|
  @ordered[key] = @unordered[key]
end

4
นี่คือวิธีที่คุณจะทำเช่นนี้หากทับทิมไม่มีวิธีการเช่น Hash # sort_by
boulder_ruby

0

ฉันมีปัญหาเดียวกัน (ฉันต้องเรียงลำดับอุปกรณ์ตามชื่อของพวกเขา) และฉันแก้ไขเช่นนี้:

<% @equipments.sort.each do |name, quantity| %>
...
<% end %>

@equipments เป็นแฮชที่ฉันสร้างในแบบจำลองของฉันและกลับไปที่คอนโทรลเลอร์ของฉัน หากคุณโทรหา. มันจะเรียงลำดับแฮชตามค่าของมัน


-3

ฉันชอบวิธีแก้ปัญหาในโพสต์ก่อนหน้า

class AlphabeticalHashฉันทำมินิคลาสเรียกมันว่า นอกจากนี้ยังมีวิธีการที่เรียกว่าapซึ่งยอมรับอาร์กิวเมนต์หนึ่งที่Hashเป็น ap variableinput: คล้ายกับ pp ( pp variable)

แต่มันจะ (ลองและ) พิมพ์ในรายการตัวอักษร (กุญแจ) Dunno ถ้าใครต้องการใช้มันใช้ได้มันเป็นอัญมณีคุณสามารถติดตั้งได้เช่น:gem install alphabetical_hash

สำหรับฉันมันง่ายพอ หากผู้อื่นต้องการฟังก์ชั่นเพิ่มเติมแจ้งให้ฉันทราบฉันจะรวมไว้ในอัญมณี

แก้ไข: เครดิตไปถึงปีเตอร์ซึ่งทำให้ฉันมีความคิด :)

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