2015-09-09 9 views
6

私は2つの配列を持っています。彼らは異なる属性を持っています。Rubyのハッシュ配列の比較とソート

array1 = [{name: "apple", quantity: 2}, {name: "grape", quantity: 10}, {name: "pear", quantity: 3}] 
array2 = [{name: "grape", freshness: 9}, {name: "apple", freshness: 7}, {name: "pear", freshness: 10}] 

私は名前で、array2の順序に基づいてarray1をソートしたいと思います。結果は次のようになります。

array1 = [{name: "grape", quantity: 10}, {name: "apple", quantity: 2}, {name: "pear", quantity: 3}] 
+0

号。それはすでに答えがあります。 – user3591126

+1

名前は両方のアレイでユニークで同一ですか? – Stefan

+0

["\ [ruby \]配列を別の配列に基づいてソートする"](http://stackoverflow.com/search?q=%5Bruby%5D+sort+array+based+on+another+array)この質問の他のバージョンを見つけるでしょう。 –

答えて

5

ここにあなたの現在のデータ構造与えられ、それを行うための簡単な方法があります。

array1 = array1.sort_by { |x| array2.find_index { |y| y[:name] == x[:name] } } 

ただし、find_indexはO(n)時間かかることに注意してください。これは、データに異なるモデルを使用するか、いくつかの前処理(例:Stefanの回答を参照)を行うことで改善できます。

5
h = array1.each_with_object({}){|e, h| h[e[:name]] = e} 
array1 = array2.map{|e| h[e[:name]]} 
+1

'sort'を使わないでソートすると、何が起こっているのか理解しています:-) – Stefan

+0

@Stefan私は 'array1'を適切な構造に変更することを考えました。あなたは 'array2'の変更を検討しました。視点からすれば、 'array1'を並べ替えることです。あなたの答えはもっと意味があるかもしれません。 – sawa

7

あなたはname => indexハッシュ構築できる:一方、大きなアレイの場合

array1.sort_by { |e| h[e[:name]] } 
#=> [{:name=>"grape", :quantity=>10}, {:name=>"apple", :quantity=>2}, {:name=>"pear", :quantity=>3}] 
+0

ベンチマークはこれが十分ではないと言っています:) – mudasobwa

2
array2.map { |h2| array1.detect { |h1| h1[:name] == h2[:name] } } 

require 'benchmark' 

@array1 = [{name: "apple", quantity: 2}, {name: "grape", quantity: 10}, {name: "pear", quantity: 3}] 
@array2 = [{name: "grape", freshness: 9}, {name: "apple", freshness: 7}, {name: "pear", freshness: 10}] 

n = 500_000 
Benchmark.bm do |x| 
    x.report {n.times { @array2.map { |h2| @array1.detect { |h1| h1[:name] == h2[:name] } } } } 
    x.report {n.times { @array1.sort_by { |x| @array2.find_index { |y| y[:name] == x[:name] } } } } 
    x.report {n.times { h = @array1.each_with_object({}){|e, h| h[e[:name]] = e} ; @array1 = @array2.map{|e| h[e[:name]] } } } 
    x.report {n.times { h = @array2.map { |e| e[:name] }.each_with_index.to_h ; @array1.sort_by { |e| h[e[:name]] } }} 
    x.report {n.times { @array1.each_with_object({}) { |g,h| h[g[:name]] = g }.values_at(*@array2.map { |g| g[:name] }) }} 
end 

    user  system  total  real 
0.960000 0.000000 0.960000 ( 1.064233) 
1.040000 0.020000 1.060000 ( 1.291731) 
0.850000 0.000000 0.850000 ( 1.064816) 
1.680000 0.000000 1.680000 ( 2.131733) 
0.840000 0.000000 0.840000 ( 1.057844) 

@:そのハッシュによって

h = array2.map { |e| e[:name] }.each_with_index.to_h 
#=> {"grape"=>0, "apple"=>1, "pear"=>2} 

ソートをsawaと@Stefanは同じように良い結果を出しました(Caryのsolutイオン):私はできません

100.times { |i| @array1 << {name:i}; @array2 << {name:i} } 
@array1.shuffle! 
@array2.shuffle! 

    user  system  total  real 
5.970000 0.000000 5.970000 ( 6.154653) 
4.980000 0.010000 4.990000 ( 5.111118) 
0.450000 0.010000 0.460000 ( 0.469722) 
0.640000 0.010000 0.650000 ( 0.655721) 
0.480000 0.010000 0.490000 ( 0.490590) 
+0

大きな配列のベンチマークを試みてください: '100x {| i | @ array1 << {名前:i}; @ array2 << {名前:i}} ' – Stefan

+0

入手しました。更新されたベンチマーク。ありがとう。 – mudasobwa

+0

私は今投稿したものを追加できますか?これは、より大きなアレイの場合に比較的速く見える。 –

1
array1.each_with_object({}) { |g,h| h[g[:name]] = g }. 
    values_at(*array2.map { |g| g[:name] }) 
    #=> [{:name=>"grape", :quantity=>10}, {:name=>"apple", :quantity=>2}, 
    # {:name=>"pear", :quantity=>3}] 
関連する問題