如何在Ruby

时间:2017-01-12 10:08:51

标签: ruby loops for-loop

我对Ruby的语法感到惊讶,我只能用一个词来描述:舒服。

编辑:我想我不清楚。我想要一种简单的方法来退出有条件的循环。

可悲的是,我找不到如何在Ruby中使用这个Java代码:

假设: 数组= [1,2,3,4] array2 = [1,2,3,4]

boolean condition = false;
for(int i = 0; i < array.length && !condition; i++)
{
  for(int j = 0; j < array2.length && !condition; j++)
  {
     condition = (array[i] + array2[j] + 1 == 7);
  }
}

if(condition)
{
  System.out.println("Two elements of the arrays + 1 sum 7")
}

我喜欢Ruby的一个衬里......但是我甚至不能用完全开环来做这个......

我正在寻找类似这样的东西(each_while组成):

array.each_while(condition && condition2) { SomeAction }

在Ruby中执行此操作的最简单方法是什么?

我使用的大多数循环都有退出条件来优化它们。我在互联网上找到的所有东西都不能被Ruby的漂亮语法所接受,因为它比Java更糟糕,我们都知道Java并不漂亮。

我在网上找到了一些解决方案:

catch "BreakOuterLoop" do
  for i in 1..10
    print "out #{i}\n"
    for j in 1..10
      print "in #{j}\n"
      throw "BreakOuterLoop" if i+j > 16
    end
  end
end

太糟糕了......

4 个答案:

答案 0 :(得分:3)

循环条件

您可以使用break

array1.each do |x|
  break unless condition && condition2
    array2.each do |y|
      break unless condition3
      # do_something
    end
  end
end

如果您需要条件中的指数:

array1.each_with_index do |x,i|
  break unless condition && condition2
    array2.each_with_index do |y,j|
      break unless condition3
      # do_something
    end
  end
end

具体问题

布尔

对于您的更新问题,您可以使用any?。这正是你想要做的。只要条件不是true,它就会迭代,并返回一个值ASAP:

array  = [1,2,3,4]
array2 = [1,2,3,4]

puts array.product(array2).any?{|a,b| a + b + 1 == 7 }
#=> true

或者:

puts array.any?{|a| array2.any?{ |b| a + b + 1 == 7 } }
#=> true

puts array.any?{|a| array2.any?{ |b| a + b + 1 == 12 } }
#=> false

第二个示例应该更快,因为并非每个对都被创建:只要找到一个,就会返回true

如果您想知道条件为true的哪一对,您可以使用find

p array.product(array2).find { |a, b| a + b + 1 == 7 }
#=> [2,4]

p array.product(array2).find { |a, b| a + b + 1 == 12 }
#=> nil

大型数组的优化

对于大型数组,上述代码运行缓慢。

您可以将最大的数组转换为Set,并使用直接查找:

require 'set'

array  = [1, 2, 3, 4]
array2 = [1, 2, 3, 4]
set2 = array2.to_set

sum = 7 - 1
x1 = array.find { |x| set2.include?(sum - x) }

if x1
  puts "#{x1} + #{sum - x1} + 1 = #{sum + 1}"
end

#=> 2 + 4 + 1 = 7

答案 1 :(得分:3)

require 'matrix'

Matrix[0...rows, 0...cols].each_with_index do |e, row, col|
  next unless [cond1, cond2, cond3].reduce :&
  # code
end
array1.each.with_index.lazy.take_while { cond1 }.each do |e1, i1|
  array2.each.with_index.lazy.take_while { cond2 }.each do |e2, i2|
    # do some stuff
  end
end

答案 2 :(得分:0)

array.length.times do |i|
  break unless condition_1 && condition_2
  # some action
end
只要条件不再符合,

break就会停止循环

关于循环矩阵

当然你可以在循环中的循环中嵌套循环,但这绝对不是 ruby​​方式。我确信对于可能出现的任何问题都有更好的解决方案。

答案 3 :(得分:0)

如前所述,对于您可以想到的任何特定用例,都有一个更漂亮的功能解决方案。我将尝试回答更一般的问题,即如何转换此java代码:

int somethingYouWillMutate = 0; // any types or values or number of things
for(int i = 0; i < array.length && condition && condition2; i++) {
  for(int j = 0; j < array2.length && condition; j++) {
     someAction(array[i], array2[j], somethingYouWillMutate);
  }
}

红宝石:

something_you_will_mutate = 0
array.product(array2).each do |e1, e2|
  break unless condition && condition2

  some_action(e1, e2)
end

注意

while c1 && c2 =:=
while true; break if !(c1 && c2) =:=
while true; break unless c1 && c2

如果你也想要指数:

array_indexed  = array.each_with_index.to_a
array2_indexed = array2.each_with_index.to_a

array_indexed.product(array2_indexed).each do |(e1, i1), (e2, i2)|
  break unless condition && condition2

  some_action(e1, e2, i1, i2, something_you_will_mutate)
end

注意:如果您想要更通用的解决方案(例如,包含3个或更多数组):

[array, array2, array3...].
  map(&:each_with_index).
  map(&:to_a).
  reduce(:product).
  map(&:flatten).
  each do |e1, i1, e2, i2, e3, i3...|
    break unless condition && condition2 && condition3...

    some_action(e1, e2, i1, i2, e3, i3..., something_you_will_mutate)
  end