【问题标题】:I have a Ruby array of objects, how to change this array into multiple arrays based on the property of those objects?我有一个 Ruby 对象数组,如何根据这些对象的属性将此数组更改为多个数组?
【发布时间】:2012-02-24 20:45:40
【问题描述】:

根据原始数组中对象的属性,将一个大数组变为多个子数组的最佳方法是什么?例如我有一个对象数组(所有对象都具有相同的属性):

array = [
    {:name => "Jim", :amount => "20"},
    {:name => "Jim", :amount => "40"},
    {:name => "Jim", :amount => "30"},
    {:name => "Eddie", :amount => "7"},
    {:name => "Eddie", :amount => "12"},
    {:name => "Pony", :amount => "330"},
    {:name => "Pony", :amount => "220"},
    {:name => "Pony", :amount => "50"}
]

请注意,所有具有相同 name 属性的对象在数组中都是连续的。现在我想根据 name 属性将对象分组到子数组中。我需要的是:

result = [
    [
        {:name => "Jim", :amount => "20"},
        {:name => "Jim", :amount => "40"},
        {:name => "Jim", :amount => "30"}
    ],
    [
        {:name => "Eddie", :amount => "7"},
        {:name => "Eddie", :amount => "12"}
    ],
    [
        {:name => "Pony", :amount => "330"},
        {:name => "Pony", :amount => "220"},
        {:name => "Pony", :amount => "50"}
    ]
]

最好的方法是什么? 谢谢。

【问题讨论】:

    标签: ruby arrays algorithm


    【解决方案1】:

    使用group_by 进行繁重的工作,然后使用map 提取您想要的内容:

    result = array.group_by { |h| h[:name] }.map { |k, v| v }
    

    例如:

    >> results = array.group_by { |h| h[:name] }.map { |k, v| v }
    >> pp results
    [[{:name=>"Jim", :amount=>"20"},
      {:name=>"Jim", :amount=>"40"},
      {:name=>"Jim", :amount=>"30"}],
     [{:name=>"Eddie", :amount=>"7"},
      {:name=>"Eddie", :amount=>"12"}],
     [{:name=>"Pony", :amount=>"330"},
      {:name=>"Pony", :amount=>"220"},
      {:name=>"Pony", :amount=>"50"}]]
    

    您也可以跳过map,直接转到Hash#values

    result = array.group_by { |h| h[:name] }.values
    

    感谢 KandadaBoggu 指出这一疏忽。

    【讨论】:

    • 也许你可以通过在group_by结果上调用values来进一步缩短这个时间,即array.group_by{ |h| h[:name] }.values
    • @KandadaBoggu:是的,这行得通,我有点尴尬,因为我没有先看到。
    【解决方案2】:

    如果具有相同 :name 值的哈希始终是连续元素,您可以这样做:

    result = array.each_with_object([]) do |e, memo|
      if memo.last && memo.last.last[:name] == e[:name]
        memo.last << e
      else
        memo << [e] 
      end 
    end
    

    或者您可以使用Enumerable#chunk(再次考虑到具有相同:name 值的元素是连续的):

    result = array.chunk{ |e| e[:name] }.map(&:last)
    

    【讨论】:

    • 请注意,在 Ruby 1.9 之前的版本中,不保证哈希值按给定顺序排列。所以在那种情况下,就不会有“永远连续”这样的事情了。
    • 你是对的,但在这种特殊情况下,我们正在迭代一个数组,而哈希恰好是它的元素。所以没有什么可担心的。我相信即使在 Ruby 的第一个版本中,数组也是有序的 =)
    • 啊,是的!哈希数组 - 抱歉 :-)
    猜你喜欢
    • 2019-09-09
    • 2021-04-21
    • 1970-01-01
    • 2020-08-15
    • 2015-03-14
    • 1970-01-01
    • 1970-01-01
    • 2021-12-07
    • 2019-09-30
    相关资源
    最近更新 更多