给定以下散列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]
我错过了什么?
答案 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#+
。