从数组作为值获取数组

时间:2017-02-16 00:27:23

标签: arrays ruby hash enumerable

给定以下散列hash,其中键作为符号,值作为数组:

hash
#=> {:stage_item=>[:stage_batch_id, :potential_item_id], :item=>[:id, :size, :color, :status, :price_sold, :sold_at], :style=>[:wholesale_price, :retail_price, :type, :name]}

如何获得仅添加了值(数组)的数组?

我知道我可以使用#each_with_object#flatten

hash.each_with_object([]) { |(k, v), array| array << v }.flatten
#=> [:stage_batch_id, :potential_item_id, :id, :size, :color, :status, :price_sold, :sold_at, :wholesale_price, :retail_price, :type, :name]

但我期待只有#each_with_object才能工作:

hash.each_with_object([]) { |(k, v), array| array += v }
#=> []

我虽然每个with对象的要点是它跟踪累加器(在这种情况下名为array),所以我可以+=在下面的例子中如下:

arr = [1,2,3]
#=> [1, 2, 3]
arr += [4]
#=> [1, 2, 3, 4]

我错过了什么?

2 个答案:

答案 0 :(得分:4)

Array << ..就地更改原始数组:

irb(main):014:0> a = original = []
=> []
irb(main):015:0> a << [1]
=> [[1]]
irb(main):016:0> a
=> [[1]]
irb(main):017:0> original
=> [[1]]
irb(main):018:0> a.equal? original  # identity check
=> true

while,Array += ..返回一个新数组而不更改原始数组:

irb(main):019:0 a = original = []
=> []
irb(main):020:0> a += [1]
=> [1]
irb(main):021:0> a
=> [1]
irb(main):022:0> original
=> []
irb(main):023:0> a.equal? original
=> false

根据Enumerable#each_with_object documentation

  

使用任意对象迭代每个元素的给定块   给定,返回最初给定的对象。

     

如果没有给出阻止,则返回一个枚举器。

因此,在+=的情况下,返回未修改的初始空数组。

顺便说一下,你可以简单地使用Hash#values method来代替使用each_with_object,它返回一个填充了哈希值的新数组:

hash.values.flatten

答案 1 :(得分:2)

如果您坚持使用inject,这实际上是Array#+更合适的情况:

hash.inject([]) { |a, (_, v)| a + v }

您通常使用each_with_object而不是inject的原因是您希望在原地累积结果而不是使用块的返回值作为累加器。在这种情况下,array1 + array2返回连接,因此您不需要使用修改备忘录对象的运算符(或方法),因为Array#+会返回您想要输入到下一个循环的内容。

虽然我们在这里,但这些更简单:

hash.values.flatten
hash.values.inject(:+)
h.values.flat_map(&:itself)

如果您真的想调用该方法,则第二个甚至使用Array#+