キーでハッシュをソートし、Rubyでハッシュを返す


258

これはハッシュを並べ替えて、(配列の代わりに)Hashオブジェクトを返す最良の方法でしょうか?

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、反復したりしない限り、ハッシュをソートすることには多くの利点があるとは思いません。それでも、おそらくキーを取得し、それらを並べ替えて、必要に応じてそれらを繰り返して値を取得します。これにより、古いルビーでコードが正しく動作するようになります。
Tin Man、

Ruby 1.9でも理にかなっています。私はdbから来た(キーとして)日付でグループ化されたアポイントメントのコレクションを持っていて、ルビーで手動でソートしました。例えば。{"2012-09-22":[...]、 "2012-09-30":[...]、 "2012-10-12":[...]}
Adit Saxena '19

はい、私はあなたのHash [h.sort]プロセスがキーをソートしてからソートされたキーを介してハッシュに再度アクセスするよりも効果的であると思います。
Douglas


3
あなたはあなたの解決策について考えるために数年を過ごしました、あなたは答えを受け入れる準備ができていますか?;-)
マークトーマス

回答:


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 2016

誰かがハッシュの配列をソートする方法を探している場合に備えて、これはトリックを実行します(hは配列です)h.map(&:sort).map(&:to_h)
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

しかし、要約すると、ソートされたハッシュについて話しても意味がありません。docsから、「キーまたは値のどちらかでハッシュをトラバースする順序は任意に見える可能性があり、通常は挿入順序にはなりません。」そのため、ハッシュに特定の順序でキーを挿入しても効果がありません。


これは正しいです。RBtree gemを使用して、Rubyの順序付きセット機能を取得することをお勧めします。
アーロンスクラッグス

26
1.9.2以降のハッシュ挿入順序は保持されます。redmine.ruby-lang.org/issues/show/994
David

4
「1.9.2から始まるハッシュの挿入順序は保持されます。」そしてそれはすばらしいです。
Tin Man

2
私の最初のコメント(おもしろい感じ)について:たとえば、ハッシュの順序付けに依存すると、1.9.2より前のバージョンのRubyでは、暗黙のうちに予期せず中断します。
Jo Liss、

5
OPの質問の2つの部分のうちの1つでも答えずに、この答えが20 +1をどのように得たのですか?"1)これは(OPの例)ハッシュをソートする最良の方法でしょうか?2)ハッシュオブジェクトを返しますか??私は+1がうらやましいわけではありません:)答えを読んだ直後で、元の質問はまだ残っています。また、ポイントは、この質問への回答選びだしのコメントでソートされたハッシュルックのようなものがないということであればstackoverflow.com/questions/489139/...
jj_

64

私はいつも使ってきましたsort_by。ハッシュを#sort_by出力するHash[]には、出力をラップする必要があります。そうしないと、配列の配列が出力されます。あるいは、これを達成#to_hするために、タプルの配列に対してメソッドを実行して、それらを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ハッシュを数値でソートする方法」にも同様の質問があります


8
sort_byハッシュで使用すると、配列が返されます。もう一度ハッシュとしてマップする必要があります。Hash[hsh.sort_by{|k,v| v}]
stevenspiel 2014年

1
はい、列挙クラスはハッシュを配列と解釈します
boulder_ruby 2014年

3
右、ソートは値です:hsh.sort_by(&:last).to_h => {"b"=>10, "a"=>1000, "c"=>200000}
Cary Swoveland、2014

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
奇妙なことに、これはRuby 1.9.3のstackoverflow.com/a/17331221/737303の「キーの並べ替え」よりもわずかに速く実行されます。
窒素

9

キーでハッシュをソートし、Rubyでハッシュを返す

非構造およびハッシュ#ソート

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を使用したくない場合や、独自の回避策を導入したくない場合の別のオプションです。


リンクが壊れている
スネークサンダース

3
一部の歴史家が過去にこれがどのように行われたかを調査したい場合に備えて、Googleを指すようにリンクを修正しました。しかし、これに取り組む人は誰でも、より新しいバージョンのRubyを使用しているはずです。
eremite

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

4
これは、ルビーは、ハッシュ#sort_byのようなメソッドを持っていなかった場合は、これを行うだろうかある
boulder_ruby

0

私は同じ問題を抱えていました(私は自分の機器を名前で並べ替えなければなりませんでした)、私はこのように解決しました:

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

@equipmentsは、モデルに基づいて構築し、コントローラーに返すハッシュです。.sortを呼び出すと、キーの値に基づいてハッシュがソートされます。


-3

以前の投稿の解決策が気に入りました。

私はそれと呼ばれるミニクラスを作りましたclass AlphabeticalHash。またap、1つの引数a Hashを入力として受け入れると呼ばれるメソッドもありますap variable。似ているpp(pp variable

しかし、それは(試行して)アルファベット順のリスト(そのキー)で印刷します。Dunno他の誰かがこれを使用したい場合は、gemとして入手できます。次のようにインストールできます。gem install alphabetical_hash

私にとって、これは十分に簡単です。他の人がより多くの機能を必要とするなら、知らせてください、私はそれを宝石に含めます。

編集:クレジットは、私にアイ​​デアを与えたピーターに送られます。:)

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.