【问题标题】:Nested Hashes and method reuse嵌套哈希和方法重用
【发布时间】:2015-08-14 09:03:26
【问题描述】:

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

有没有使用方法的 DRY 方法来做到这一点?

我还希望最终输出出现在表格中,最好的方法是什么?这就是为什么我最初有多个 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/

【问题讨论】:

  • 请在您的预期输出中编辑一些示例输入。我们可以从你乱七八糟的 if 语句中推断出来,但我们不希望这样做。此外,与您的问题没有直接关系,但您正在滥用 ERb。您的模板中不应该有这么多代码。尤其不是方法定义。模板的全部目的是将代码与标记分开(参见 MVC 和关注点分离)。
  • 嗯,这就是我需要这个方法的原因,所以我可以把它放在控制器中并消除混乱。
  • 我理解第二个sn-p中的混乱;这就是你想要做的。这是我反对的第一个 sn-p,它显然是在视图中,而不是在控制器中。
  • 啊,中肯的评论,那是因为我从视图中复制了if语句只是为了快速放在这里,添加了示例数据。
  • 所以你只想要所有东西的键和值,用中断分隔? (你没有给出预期的输出。你不需要做所有事情,但前几行会很棒。)

标签: ruby methods hash iteration dry


【解决方案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 混入控制器中。

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

【讨论】:

  • 这没用,数据重复了好几次,格式都出错了,理想情况下我希望它输出到表格中。
  • 数据结构中只有重复的数据才能重复。格式与您在第一篇文章中指定的完全一样。这正是我多次要求在您的问题中提供输出示例的原因——不是“概念”版本,而是您期望获得的 HTML。我不知道您如何想象将其放入表格中(更不用说到目前为止您的问题的任何版本都没有提到表格)。而且,nestedHashName 不会出现在您的数据中的任何位置。
  • 抱歉,我没想到在将结构添加到多次迭代时事情会变得更加复杂。
  • 他们不是。但我不能回答你没有提出的问题——不是心灵感应者,在这里。如果您可以根据您提出的问题调整答案,那就太好了(而且做起来相当简单)。如果你不能,那么你可以提出一个问题,让答案是你可以使用的。这是XY problem:如果你想要一张桌子,为什么要问&lt;br&gt;
  • 另外 - 您最近的 HTML 示例将没有缩进,这不会显示您所在的级别。这是你想要的吗?此时,您最好制作一个 jsfiddle 或 Stack Overflow 代码 sn-p - 一个您可以在屏幕上实际看到的 HTML 模型,而不是“概念化”,并调整您想要的视觉外观。并使用正确的、真实的数据(不一定是全部,但不是像“key value”和“nestedHashName”这样的虚构数据)。
猜你喜欢
  • 2015-04-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-03-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多