2016-05-25 6 views
-2

この「ハッシュの配列」からの「分析」値を再帰で合計する方法は不思議です。このハッシュの配列を再帰させる方法

入力:

[{"id"=>"1234", 
    "id_data"=> 
     [{"segment"=>{"segment_name"=>"Android"}, 
     "metrics"=> 
      { 
      "logins"=>[1000, 2000], 
      "sign_ups_conversion"=>{ 
       "count"=>[500, 200], 
       "cost"=>[2, 4] 
      } 
      }, 
     }, 
     {"segment"=>{"segment_name"=>"iOS"}, 
     "metrics"=> 
      { 
      "logins"=>[5000, 10000], 
      "sign_ups_conversion"=>{ 
       "count"=>[100, 50], 
       "cost"=>[6, 8] 
      } 
      }, 
     } 
     ] 
    }, 
    {"id"=>"5678", 
    "id_data"=> 
     [{"segment"=>{"segment_name"=>"Android"}, 
     "metrics"=> 
      { 
      "logins"=>[3000, 2000], 
      "sign_ups_conversion"=>{ 
       "count"=>[300, 400], 
       "cost"=>[2, 4] 
      } 
      }, 
     }, 
     {"segment"=>{"segment_name"=>"iOS"}, 
     "metrics"=> 
      { 
      "logins"=>[5000, 10000], 
      "sign_ups_conversion"=>{ 
       "count"=>[100, 50], 
       "cost"=>[6, 8] 
      } 
      }, 
     } 
     ] 
    }] 

出力:

{ 
     "Android"=>{ 
     "ids" => ['1234','5678'], 
     "segment" => {"segment_name"=>"Android"}, 
     "id_data" => [{ 
      "logins" => [4000, 4000], # sum by index from 'Android' logins ("logins"=>[1000, 2000] & "logins"=>[3000, 2000]), 
      "sign_ups_conversion" => { 
       "count" => [800, 600], # sum by index from 'Android' sign ups count ("count"=>[500, 200] & "count"=>[300, 400]) 
       "cost" => [4, 8] # sum by index from 'Android' sign ups cost ("cost"=>[2, 4] & "cost"=>[2, 4]) 
      } 
     }] 
     }, 
     "iOS"=>{ 
     "ids" => ['1234','5678'], 
     "segment" => {"segment_name"=>"iOS"}, 
     "id_data" => [{ 
      "logins" => [10000, 20000], # sum by index from 'iOS' logins ("logins"=>[5000, 10000] & "logins"=>[5000, 10000]), 
      "sign_ups_conversion" => { 
       "count" => [200, 100], # sum by index from 'iOS' sign ups count ("count"=>[100, 50] & "count"=>[100, 50]) 
       "cost" => [12, 16] # sum by index from 'iOS' sign ups cost ("cost"=>[6, 8] & "cost"=>[6, 8]) 
      } 
     }] 
     } 
    } 

私は、この方法でそれを解決しようとしているが、それは、ハッシュ形式(sign_ups_conversion)で分析を数え、まだ把握されていません結果がどのように出力に等しくなるべきかを示します。

def aggregate_by_segments(stats_array) 
     results = {} 

     stats_array.each do |stats| 
     stats['id_data'].each do |data| 
      segment_name = data['segment']['segment_name'] 
      results[segment_name] ||= {} 
      (results[segment_name]['ids'] ||= []) << stats['id'] 
      results[segment_name]['segment'] ||= data['segment'] 
      results[segment_name]['id_data'] ||= [{}] 
      data['metrics'].each do |metric, values| 
      next if skip_metric?(values) 
      (results[segment_name]['id_data'][0][metric] ||= []) << values 
      end 
     end 
     end 
     sum_segments(results) 
    end 

    def sum_segments(segments) 
     segments.each do |segment, segment_details| 
     segment_details['id_data'][0].each do |metric, values| 
      segment_details['id_data'][0][metric] = sum_segment_metric(values) 
     end 
     end 
     segments 
    end 

    def sum_segment_metric(metric_value) 
     metric_value.transpose.map { |x| x.reduce(:+) } 
    end 

    # I skipped hash format for now 
    def skip_metric?(metric_values) 
     !metric_values.is_a? Array 
    end 

    ############################################ 
    # calls it with aggregate_by_segments(input) 
    ############################################ 

私たちは再帰を使用する必要があると考えているが、私はまだ誰も私を助けることができる、それを考え出しますよ?

ありがとうございます!

+5

これはかなり複雑なコードセットで、人々にあなたに解決策を教えてくれるように頼んでいます。いずれにせよ、大きな問題を解決する方法は、いくつかの小さな問題に分解することです。なぜそれをしないのですか?それをより消化しやすい部分に分解することで、範囲の狭い具体的な質問をタイムリーに回答する可能性が高くなります。どのような部品*があれば、それは働きますか?どのような部分はありませんか?では、最初のマイルストーンは何でしょうか? (ちょっと、私はあなたが再帰を必要とするとは思わない) –

+5

非常に大きいだけでなく、あなたのサンプルデータは特定のものです。より一般的な(そしてより小さな)構造を投稿することを検討してください。 – Stefan

+1

もう一つ役立つかもしれないことは、何が起こる必要があるのか​​、普通の英語で書くことができるということです。また、ゴム製のダックの力を過小評価することもありません。 ;)(https://en.wikipedia.org/wiki/Rubber_duck_debugging) –

答えて

0

私はそれを解決しました。

def aggregate_by_segments(stats_array) 
     results = {} 

     stats_array.each do |stats| 
     stats['id_data'].each do |data| 
      segment_name = data['segment']['segment_name'] 
      results[segment_name] ||= {} 
      (results[segment_name]['ids'] ||= []) << stats['id'] 
      results[segment_name]['segment'] ||= data['segment'] 
      results[segment_name]['id_data'] ||= [{}] 
      data['metrics'].each do |metric, values| 
      hash_values(results[segment_name]['id_data'][0], metric, values) if values.is_a? Hash 
      next if skip_metric?(values) 
      (results[segment_name]['id_data'][0][metric] ||= []) << values 
      end 
     end 
     end 
     sum_segments(results) 
    end 

    def hash_values(metrics, metric, hash_values) 
     hash_values.each do |k, v| 
     next if skip_metric?(v) 
     metrics[metric] ||= {} 
     (metrics[metric][k] ||= []) << v 
     end 
    end 

    def sum_segments(segments) 
     segments.each do |segment, segment_details| 
     segment_details['id_data'][0].each do |metric, values| 
      segment_details['id_data'][0][metric] = sum_segment_metric(values) 
     end 
     end 
     segments 
    end 

    def sum_segment_metric(metric_value) 
     result = metric_value.transpose.map { |x| x.reduce(:+) } if metric_value.is_a? Array 
     result = metric_value.each do |k, v| 
     metric_value[k] = sum_segment_metric(v) 
     end if metric_value.is_a? Hash 
     result 
    end 

    def skip_metric?(metric_values) 
     !metric_values.is_a? Array 
    end 

私はコードがかなり醜いことを知っています。私は後でそれをリファクタリングします:)

建設的なフィードバックを訪問してコメントをいただきありがとうございました。

0

問題ここでは、このデータ構造をアクセスもする方法である、ルビー戦略は、それぞれを使って、配列を反復処理し、このような連結のハッシュでキーをconctenatingすることができます。

あなたの構造がmantainedされていることを仮定すると:

配列[hash [array [hash]]

array_hash.each do |stats| 
    stats["id_data"].each do |h| 
    puts h["metrics"]["sign_ups_conversion"] 
    end 
end 
# => {"count"=>[500, 200], "cost"=>[2, 4]} 
# => {"count"=>[100, 50], "cost"=>[6, 8]} 
# => {"count"=>[300, 400], "cost"=>[2, 4]} 
# => {"count"=>[100, 50], "cost"=>[6, 8]} 
+0

答えていただきありがとうございます:) – Ardian

関連する問題