2

我有一堂课Test

class Test 
  attr_accessor :data
  def initialize
    @data = [0, 1, 2, 3]
  end
  def map
    @data.map!{|i| i = yield i }
  end
end

我尝试像这样使用它:

a = Test.new

a.map{|i|
  if(i==2)
    i+=1
    break i  #<--- -This line is the focus
  else
    1
  end
}

puts a.data

我期望的输出是[1, 1, 3, 3]. 相反,我得到[1, 1, 2, 3]. 块的最后一次迭代map不返回修改后的i.

我替换break inext i. 这按我的预期执行,并产生了输出[1, 1, 3, 1]

如何修改这段代码(或者,理想情况下,我在第二个代码片段中指出的行)以便获得输出[1, 1, 3, 3]?换句话说,我怎样才能使块完成,但将最后一个值传回map?是否有一种简洁易读的方式来做到这一点(例如,切换布尔标志break_now)?

4

3 回答 3

1

我假设您问的是如何离开一个块并使用计算出的最后一个值,而不是如何计算一组特定的数字;对于后者,可能有一个聪明的单线。

像这样的东西怎么样:

class Test
  attr_accessor :data

  def initialize
    @data = [0, 1, 2, 3]
  end

  def modify
    @data.map! {|i| yield i }
  end
end

a = Test.new
a.modify do |i|
  break i if @done
  @done = i == 2
  @done ? (i + 1) : 1
end

puts a.data

另一个想法#map是 Ruby 中具有特定接口的重要方法。在您的示例中,您通过修改Test. 出于这个原因,我改用了这个名字#modify

于 2012-12-09T04:27:35.607 回答
0

通常,您可以通过适当地修改产生的值来解决这个问题。例如,如果您的数组由字符串而不是 Fixnums 组成:

class Test
  attr_accessor :data

  def initialize
    @data = %w{a b c d}
  end

  def map
    @data.map! { |i| yield i }
  end
end

a = Test.new
a.map do |i|
  if i == 'c'
    i.next!
    break
  else
    'b'
  end
end

p a.data   #=> ["b", "b", "d", "d"]

您的示例的问题

Fixnum 对象具有直接的价值。这意味着当它们被分配或作为参数传递时,传递的是实际对象,而不是对该对象的引用。赋值不对 Fixnum 对象起别名。对于任何给定的整数值,实际上只有一个 Fixnum 对象实例……</p>

Fixnums 不能就地更改,因此您i += 1在下部块中的表达式不会影响i上部块中的值。这就是为什么你2在你的例子中但d在我的例子中。

于 2012-12-09T05:49:09.080 回答
-1

你必须这样做:

a.map{ |i| (i % 2 == 0) ? i + 1 : i }

当您使用地图功能时,您不会更改“a”变量,如果您想更改“a”变量,请执行以下操作:

a.map!{ |i| (i % 2 == 0) ? i + 1 : i }

'i' 的新值是块返回的值,所以不要这样做:

a.map{|i| i = 1 }

因为如果你这样做:

a.map{|i| i = 1; 5 }

结果将是:

 [5, 5, 5, 5]
于 2012-12-09T04:23:08.100 回答