将哈希值更改为哈希数组

时间:2016-12-27 00:59:58

标签: arrays ruby hash merge reduce

我想将这个ruby哈希结构转换为哈希数组。结束结构将在图表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]]
    }
]

2 个答案:

答案 0 :(得分:4)

<强>代码

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

然后构造“运输”的哈希值。

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

其余的计算方法类似。

答案 1 :(得分: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