了解红宝石注射

时间:2014-03-02 18:13:40

标签: ruby inject

我对这个对我不起作用的代码感到困惑。

tab=Array.new
tab<<"1,2,3"
tab<<"4"
tab<<"5,6"
x=tab.inject([]){|t,elt|

  if elt.include?(',')
    s=elt.split(',')
    s.each{|y| t<<y}
  else
    t<<elt
  end
 }
STDOUT.puts x

============= outpout:5 6 但如果我改变代码,

tab=Array.new
tab<<"1,2,3"
tab<<"4"
tab<<"5,6"
x=tab.inject([]){|t,elt|

  if elt.include?(',')
    s=elt.split(',')
    s.each{|y| t<<y}
  else
    t<<elt
  end
   t.each{|tt| tt} #i add this line

}
STDOUT.puts x

======输出:1 2 3 4 5 6 有人有解释吗? THX

2 个答案:

答案 0 :(得分:1)

#inject区块中,您将最后一个条目作为"5,6"传递。现在在if块内,您将其拆分为数组。然后,您在#each上调用了方法[5,6]。现在#each方法返回您调用它的接收器。

但在第二种情况下,您在t.each块的每次迭代的最后一次调用inject。因此,在最后一次传递t上是一个完整的数组[1,2,3,4,5,6]。现在正如我所说,Array#each返回接收者,因此你得到了t的完整[1,2,3,4,5,6]

我会把你的代码写成:

ary = ["1,2,3","4","5,6"]
ary.flat_map { |str| str.include?(",") ? str.split(',') : str }
# => ["1", "2", "3", "4", "5", "6"]

如果您想使用#inject,请执行:

ary = ["1,2,3","4","5,6"]
ary.inject([]) { |a,str| a.concat(str.split(',')) }
# => ["1", "2", "3", "4", "5", "6"]

答案 1 :(得分:0)

使用inject,每个块的返回值将传递给后续块。第一个例子,返回值是s.each{|y| t<<y}的值;最后的迭代将返回[5, 6]。你的第二个例子间接返回t; t.each { }返回t,以便可以将其他方法链接到其中。

您需要返回每个块末尾正在构建的集合:

x=tab.inject([]){|t,elt|

  if elt.include?(',')
    s=elt.split(',')
    s.each{|y| t << y}
  else
    t<<elt
  end

  t

}

然而,你可以使这个显着缩小;只需将新元素添加到现有元素,然后返回结果:

tab.inject([]) { |t, elt|
  t + elt.include?(',') ? elt.split(',') : Array[elt]
}