嵌套哈希和方法重用

时间:2015-06-01 01:19:24

标签: ruby methods hash iteration dry

我有一些我想要迭代的哈希,有些哈希嵌套哈希可以深入3-4级, 我现在正在使用if语句来检查该值是否为哈希,然后再次遍历它,但我只是在这里重复代码。

使用方法是否有干嘛方法?

此外,我希望最终输出最终出现在表格中,最好的方法是什么?这就是为什么我最初有多个if语句所以我可以添加单独的标签。

示例方法:

<% def hashTest(key, value) %>
    <% if value.is_a?(Hash) %>
        <%= key %>
            <% value.each do |key, value| %>
                <%= key %>
                <%= value %>
            <% end %>
    <% else %>
        <%= key %>
        <%= value %>
    <% end %>
<% end %>

这就是我所拥有的if语句的混乱......

<% parsed.each do |key, value| %>
    <% if value.is_a?(Hash) %>
        <%= key %>
        <br/>
        <% value.each do |key, value| %>
                <% if value.is_a?(Hash) %>
                    <%= key %>
                    <br/>
                    <% value.each do |key, value| %>
                            <% if value.is_a?(Hash) %>
                            <%= key %>
                            <br/>
                                <% value.each do |key, value| %>
                                    <%= key %>
                                    <%= value %>
                                    <br/>
                                <% end %>
                            <% else %>
                                <%= key %>
                                <%= value %>
                                <br/>
                            <% end %>
                    <% end %>
                <% else %>
                    <%= key %>
                    <%= value %>
                    <br/>
                <% end %>
        <% end %>
    <% else %>
        <%= key %>
        <%= value %>
        <br/>
    <% end %>
<% end %>

示例输入:

{
  "statement": {
    "generated": "2015-01-11",
    "due": "2015-01-25",
    "period": {
      "from": "2015-01-26",
      "to": "2015-02-25"
    }
  },
  "total": 136.03,
  "package": {
    "subscriptions": [
      { "type": "tv", "name": "Movies", "cost": 50.00 },
      { "type": "Phone", "name": "Landline", "cost": 5.00 },
      { "type": "broadband", "name": "Fibre", "cost": 16.40 }
    ],
    "total": 71.40
  },
  "callCharges": {
    "calls": [
      { "called": "07716393769", "duration": "00:23:03", "cost": 2.13 },
      { "called": "07716393769", "duration": "00:23:03", "cost": 2.13 },
      { "called": "07716393769", "duration": "00:23:03", "cost": 2.13 },
      { "called": "07716393769", "duration": "00:23:03", "cost": 2.13 },
      { "called": "07716393769", "duration": "00:23:03", "cost": 2.13 },
      { "called": "07716393769", "duration": "00:23:03", "cost": 2.13 },
      { "called": "07716393769", "duration": "00:23:03", "cost": 2.13 },
      { "called": "07716393769", "duration": "00:23:03", "cost": 2.13 },
      { "called": "07716393769", "duration": "00:23:03", "cost": 2.13 },
      { "called": "07716393769", "duration": "00:23:03", "cost": 2.13 },
      { "called": "07716393769", "duration": "00:23:03", "cost": 2.13 },
      { "called": "07716393769", "duration": "00:23:03", "cost": 2.13 },
      { "called": "07716393769", "duration": "00:23:03", "cost": 2.13 },
      { "called": "07716393769", "duration": "00:23:03", "cost": 2.13 },
      { "called": "07716393769", "duration": "00:23:03", "cost": 2.13 },
      { "called": "07716393769", "duration": "00:23:03", "cost": 2.13 },
      { "called": "07716393769", "duration": "00:23:03", "cost": 2.13 },
      { "called": "07716393769", "duration": "00:23:03", "cost": 2.13 },
      { "called": "02074351359", "duration": "00:23:03", "cost": 2.13 },
      { "called": "02074351359", "duration": "00:23:03", "cost": 2.13 },
      { "called": "02074351359", "duration": "00:23:03", "cost": 2.13 },
      { "called": "02074351359", "duration": "00:23:03", "cost": 2.13 },
      { "called": "02074351359", "duration": "00:23:03", "cost": 2.13 },
      { "called": "02074351359", "duration": "00:23:03", "cost": 2.13 },
      { "called": "02074351359", "duration": "00:23:03", "cost": 2.13 },
      { "called": "02074351359", "duration": "00:23:03", "cost": 2.13 },
      { "called": "02074351359", "duration": "00:23:03", "cost": 2.13 },
      { "called": "02074351359", "duration": "00:23:03", "cost": 2.13 }
    ],
    "total": 59.64
  },
  "Store": {
    "rentals": [
      { "title": "50 Shades of Grey", "cost": 4.99 }
    ],
    "purchases": [
      { "title": "That's what she said", "cost": 9.99 },
      { "title": "Broke back mountain", "cost": 9.99 }
    ],
    "total": 24.97
  }
}

示例输出:

https://jsfiddle.net/un5ex8y1/1/

1 个答案:

答案 0 :(得分:1)

假设您要在单独的行中显示每个键,每个值和每个数组元素,

def flatten_breakify(val)
  case val
  when Hash
    val.map { |k, v| "#{k}<br>#{flatten_breakify(v)}" }.join('<br>')
  when Array
    val.map(&method(:flatten_breakify)).join('<br>')
  else
    val
  end
end

另一种更优雅的方法:

def flatten_all(val)
  case val
  when Hash
    val.flat_map { |k, v| [k, *flatten_all(v)] }
  when Array
    val.flat_map(&method(:flatten_all))
  else
    val
  end
end

然后你可以放入你的模板

<%= flatten_all(data).join('<br>') %>

为了不将HTML混合到控制器中。

编辑:我看到你在输出中添加了缩进,这在其他地方没有提到过。我建议您使用<ul>而不是普通<br>,以实现正确的嵌套,并使用CSS解决缩进。您将无法使用第二种方法,因为它现在具有更多结构。第一段代码,因为它涉及HTML,不应该在一个控制器中,而应该在一个帮助器中(这是帮助器的用途,用于从数据生成HTML)。