【问题标题】:Changing a hash to an array of hash将哈希更改为哈希数组
【发布时间】:2017-05-11 07:17:40
【问题描述】:

我想把这个 ruby​​ 哈希结构转换成一个哈希数组。最终结构将在charts api中使用,提前致谢

发件人:

data = 
    {
        ["Transportations", "Not-Approved"] => 350,
        ["Transportations", "Approved"]     => 160,
        ["Communications",  "Not-Approved"] => 300,
        ["Communications","Approved"]       => 80,
        ["Rentals","Not-Approved"]          => 50,
        ["Rentals", "Approved"]             => 145,
        ["Salaries","Not-Approved"]         => 150,
        ["Salaries", "Approved"]            => 310
    }

收件人:

data = [
    {
        name: "Transportations",
        data: [["Not-Approved", 350], ["Approved", 160]]
    },
    {
        name: "Communications",
        data: [["Not-Approved", 300], ["Approved", 80]]
    },
    {
        name: "Rentals",
        data: [["Not-Approved", 50], ["Approved", 145]]
    },
    {
        name: "Salaries",
        data: [["Not-Approved", 150], ["Approved", 310]]
    }
]

【问题讨论】:

    标签: arrays ruby hash merge reduce


    【解决方案1】:

    代码

    def rearrange(data)
      data.group_by { |k,_| k.first }.map { |name, arr|
        { name: name, data: arr.map { |(_,outcome), val| [outcome, val] } } }
    end
    

    示例

    data = {
      ["Transportations", "Not-Approved"] => 350,
      ["Transportations", "Approved"]     => 160,
      ["Communications",  "Not-Approved"] => 300,
      ["Communications","Approved"]       => 80,
      ["Rentals","Not-Approved"]          => 50,
      ["Rentals", "Approved"]             => 145,
      ["Salaries","Not-Approved"]         => 150,
      ["Salaries", "Approved"]            => 310
    }
    
    rearrange(data)
      #=> [{:name=>"Transportations",
      #     :data=>[["Not-Approved", 350], ["Approved", 160]]},
      #    {:name=>"Communications",
      #     :data=>[["Not-Approved", 300], ["Approved", 80]]},
      #    {:name=>"Rentals",
      #     :data=>[["Not-Approved", 50], ["Approved", 145]]},
      #    {:name=>"Salaries",
      #     :data=>[["Not-Approved", 150], ["Approved", 310]]}
      #   ] 
    

    说明

    第一步如下。

    h = data.group_by { |k,_| k.first }
      #=> { "Transportations"=>[
      #       [["Transportations", "Not-Approved"], 350],
      #       [["Transportations", "Approved"], 160]
      #     ],
      #     "Communications"=>[
      #       [["Communications", "Not-Approved"], 300],
      #       [["Communications", "Approved"], 80]
      #     ],
      #     "Rentals"=>[
      #       [["Rentals", "Not-Approved"], 50],
      #       [["Rentals", "Approved"], 145]
      #     ],
      #     "Salaries"=>[
      #       [["Salaries", "Not-Approved"], 150],
      #       [["Salaries", "Approved"], 310]
      #     ]
      #   } 
    

    Enumerable#group_by 的第二个块变量保存键的值(键是第一个块变量)。例如,当键是["Transportations", "Not-Approved"] 时,值是350。我已经将块变量_(一个有效的局部变量)赋值给了该值,主要是为了告知读者它没有用于块计算。

    要理解第二步,h的键值对的映射,先定义

    enum = h.map
      #=> #<Enumerator:
      #     {"Transportations"=>[
      #        [["Transportations", "Not-Approved"], 350],
      #        [["Transportations", "Approved"], 160]
      #      ], "Communications"=>[
      #    ...
      #          [["Salaries", "Approved"], 310]]}:map>
    

    enum的第一个元素被生成并传递给块,块变量使用并行赋值赋值。

    name, arr = enum.next
      #=> ["Transportations", [
      #      [["Transportations", "Not-Approved"], 350],
      #      [["Transportations", "Approved"], 160]
      #    ]
      #   ] 
    name
      #=> "Transportations" 
    arr
      #=> [
      #    [["Transportations", "Not-Approved"], 350],
      #    [["Transportations", "Approved"], 160]
      #   ]
    

    然后执行map 的块计算。首先,计算

    a = arr.map { |(_,outcome), val| [outcome, val] }
      #=> [["Not-Approved", 350], ["Approved", 160]]
    

    然后为“Transportation”构造哈希。

    { name: name, data: a }
      #=> {:name=>"Transportations",
      #    :data=>[["Not-Approved", 350], ["Approved", 160]]} 
    

    其余计算类似。

    【讨论】:

    • 感谢您的详尽解释。会试一试
    • 这正是我尝试时想出的。
    【解决方案2】:

    试试这个,

    h = Hash.new { |h, k| h[k] = { name: k, data: {} }}
    data.each { |(name, each), value| h[name][:data][each] = value };
    h.values.each { |each| each[:data] = each[:data].to_a }
    array = h.values
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-10-27
      • 2019-05-23
      • 2012-10-29
      • 2021-02-05
      • 1970-01-01
      • 1970-01-01
      • 2015-11-26
      • 1970-01-01
      相关资源
      最近更新 更多