2017-01-18 7 views
0

私はシェフの料理本のバージョン番号が複数の異なる環境で指定されているバージョン管理システムで作業しています。Rubyの重複配列が重複しないで重複した配列の中でより高い値を使用する

私は2つの環境では、このフォーマットを使用してファイルを一緒マージすることができました -

source  = JSON.parse(File.read("A.json")) 
destination = JSON.parse(File.read("B.json")) 
source  = destination.merge(source) 

各ファイルの値は、この形式である -

「」

{ 
    "a": "v2.0.18", 
    "b": "v5.0.2", 
    "c": "v17.0.0", 
    "d": "v9.0.0", 
} 

'B'

{ 
    "a": "v1.0.18", 
    "b": "v4.0.0", 
    "c": "v20.0.0", 
    "d": "v7.0.0" 
} 

は現在ありません - 私はそれが何をしたいのですがどのような

{ 
    "a": "v2.0.18", 
    "b": "v5.0.2", 
    "c": "v17.0.0", 
    "d": "v9.0.0", 
} 

を -

{ 
    "a": "v2.0.18", 
    "b": "v5.0.2", 
    "c": "v20.0.0", #keeps higher value 
    "d": "v9.0.0", 
} 

任意の助けいただければ幸いです。 ありがとう

+0

シェフのクックブックのバージョンは、単に「x.y.z」で、先頭に「v」はありません。 – Stefan

答えて

5

Hash#mergeを使用できますが、2つの文字列の比較方法も定義する必要があります。

major_minor"v2.0.18"[2,0,18]に変換します。これは他のバージョンのアレイと比較して最大値を見つけることができます。

source = { 
    "a": "v2.0.18", 
    "b": "v5.0.2", 
    "c": "v17.0.0", 
    "d": "v9.0.0", 
} 

destination = { 
    "a": "v1.0.18", 
    "b": "v4.0.0", 
    "c": "v20.0.0", 
    "d": "v7.0.0" 
} 

def major_minor(version) 
    version.scan(/\d+/).map(&:to_i) 
end 

p source.merge(destination){|key, old, new| [old, new].max_by{|v| major_minor(v) } } 
#=> {:a=>"v2.0.18", :b=>"v5.0.2", :c=>"v20.0.0", :d=>"v9.0.0"} 
+3

'version.scan(/ \ d + /)。map(&:to_i)' wouldまた仕事 – Stefan

+0

@Stefan:ありがとう、更新されました。 'Array#<=>'が定義されていて、 'Array#>'や 'Array#<'ではないのはなぜですか? –

+4

[Matz](https://bugs.ruby-lang.org/issues/5574#note-7)によると:_ "配列は常に互換性があるわけではないので、私は配列を比較可能にすることで間違った意味を与えたくない。 <=>を追加することで、配列の並べ替えを可能にする現実的な妥協案が得られました。」_ – Stefan

2

mergeブロックを渡して、キーが複製されるときに選択する値を選択することができます。

+0

Upvoted。あなたは最初に答えてくれました。あなたの答えは技術的に正しいです。 OPはコードを書いていないので、ヒントIMHOを与えるのは大丈夫です。 –

+0

助けてくれてありがとう –

+0

あなたの質問に基づいて、あなたはヒントが必要だと思ったので、詳細を結びつけることができます。 – Bustikiller

5

Hash#mergeあなたが探しているものです:

a.merge(b) do |key, old_val, new_val| 
    Gem::Version.new(old_val[1..-1]) > Gem::Version.new(new_val[1..-1]) ? old_val : new_val 
end 
#=> {:a=>"v2.0.18", :b=>"v5.0.2", :c=>"v20.0.0", :d=>"v9.0.0"} 

@Stefanが示唆したように、上記@Eric Duminilアプローチを組み込むことによって改善することができin his answerを使用:

a.merge(b) { |key, *values| values.max_by { |v| Gem::Version.new(v[1..-1]) } } 
+2

'old' =>' old_val'です。'Gem :: Version'をうまく使います! –

+0

@EricDuminilスポッティングのおかげで - 編集されました! :) –

+0

私はEric Duminilのアプローチを取り入れていますが、niceです: 'a.merge(b){| key、* values | values.max_by {| v | Gem :: Version.new(v [1 ..- 1])}} ' – Stefan

-1

mergeは、追加の引数ブロックを使用して、保持するキーを把握します両方のハッシュが同じキーを持つ

a = { 
     "a": "v2.0.18", 
     "b": "v5.0.2", 
     "c": "v17.0.0", 
     "d": "v9.0.0", 
    } 
b = { 
     "a": "v1.0.18", 
     "b": "v4.0.0", 
     "c": "v20.0.0", 
     "d": "v7.0.0" 
    } 
c = a.merge(b) {|k, v1, v2| [v1, v2].max} 
=> {:a=>"v2.0.18", :b=>"v5.0.2", :c=>"v20.0.0", :d=>"v9.0.0"} 
+2

それは動作しません。辞書順はバージョン順ではありません。 '" v11.0 ">" v9.0 "#=> false' –

+0

注:私はdownvoteしませんでした。私は通常、コメントを書いて答えが訂正されるのを待つだけです。 –

+0

@EricDuminilフェアポイント。私はあまりにも数字で作業するのに慣れているだけで、このケースでは見つけられましたが、確かに問題を引き起こす可能性があります。 –

関連する問題