从以数组为值的散列中获取数组

Get array from hash with arrays as values

给定以下哈希 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 and #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]

我错过了什么?

Array << .. 改变原数组 in-place:

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 += .. returns 不改变原数组的新数组:

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

Iterates the given block for each element with an arbitrary object given, and returns the initially given object.

If no block is given, returns an enumerator.

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


顺便说一句,您可以简单地使用 Hash#values method 而不是使用 each_with_object,其中 returns 一个新数组填充了散列中的值:

hash.values.flatten

如果你坚持使用Array#+:

,实际上inject会更合适
hash.inject([]) { |a, (_, v)| a + v }

您通常使用 each_with_object 而不是 inject 的原因是如果您想要累加结果 in-place 而不是使用块的 return 值作为累加器。在这种情况下,array1 + array2 return 是串联,因此您不需要使用修改备忘录对象的运算符(或方法),因为 Array#+ return 是您想要的进入下一个周期。

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

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

如果你真的喜欢调用那个方法,第二个甚至使用 Array#+