【问题标题】:How to recursion this array of hashes如何递归这个哈希数组
【发布时间】:2016-09-23 03:35:06
【问题描述】:

我想知道如何通过递归对这个哈希数组中的“分析”值求和。

输入:

   [{"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)
    ############################################

我认为我们应该使用递归,但我还在想办法,有人可以帮助我吗?

提前致谢!

【问题讨论】:

  • 这是一组相当复杂的代码,需要很多人才能为您提供解决方案。无论如何,解决一个大问题的方法是把它分解成几个小问题。为什么不这样做?通过将其分解成更易于理解的部分,您可以提出范围更窄的特定问题,这些问题更有可能得到及时的回答。哪些部分确实起作用(如果有)?哪些部分没有?那么,第一个里程碑是什么? (顺便说一句,我认为您不需要递归。)
  • 除了非常大之外,您的示例数据是非常特定的。考虑发布更通用(更小)的结构。
  • 另一件可能有帮助的事情是你可以用简单的英语写下需要发生的事情。此外,永远不要低估橡皮鸭的力量。 ;) (en.wikipedia.org/wiki/Rubber_duck_debugging)
  • 而且,对于按段分组,您可以使用类似result = input.each_with_object({}) do |id_hash, res| id = id_hash['id'] id_hash['id_data'].each do |id_data| segment = id_data['segment']['segment_name'] res[segment] ||= [] res[segment] &lt;&lt; id_data.merge('id' =&gt; id) end end puts result
  • @KeithBennett 对不起,那是在午夜。是的,你是对的,问题是广泛的

标签: arrays ruby recursion hash


【解决方案1】:

这里的问题是如何访问这些数据结构,一个 ruby​​ 策略可以使用 each 和连接键与连接散列的连接来遍历数组,如下所示:

假设你的结构是维护的:

数组[哈希[数组[哈希]]

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]}

【讨论】:

  • 谢谢你的回答:)
【解决方案2】:

我解决了。

    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

我知道代码很丑。我稍后会重构它:)

感谢大家的访问和建设性反馈意见。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-03-12
    • 2013-10-10
    • 2020-11-13
    • 2016-09-21
    • 2017-09-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多