使用“注入",“除非"和“下一个"来确定最小值 [英] Using `inject`, `unless`, and `next` to determine the minimum value

查看:119
本文介绍了使用“注入",“除非"和“下一个"来确定最小值的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有此代码:

def test(vertices, distances)
  until vertices.empty?
    nearest_vertex = vertices.inject do |a, b|
      p "a = #{a}: b = #{b}"
      p "distances[a] = #{distances[a]}, distances[b] = #{distances[b]}"
      next b unless distances[a] #next b if distances[a] == true
      next a unless distances[b] #next a if distances[b] == true
      next a if distances[a] < distances[b]
      p "b = #{b}"
      b
    end
    p "nearest_vertex = #{nearest_vertex}"
    vertices.delete nearest_vertex
  end
end

vertices = [1, 2, 3, 4, 5, 6]
distances = {1 => 0, 2 => 3, 3 => 2, 4 => 18, 5 => nil, 6 => 7}
test(vertices, distances)

哪个输出:

"a = 1: b = 2"
"distances[a] = 0, distances[b] = 3"
"a = 1: b = 3"
"distances[a] = 0, distances[b] = 2"
...
"a = 1: b = 6"
"distances[a] = 0, distances[b] = 7"
"nearest_vertex = 1"

此处,未打印b = 6.这是因为next发出了停止迭代命令吗?

Here, b = 6 isn't printed. Is this because next issues a stop iteration command?

"a = 2: b = 3"
"distances[a] = 3, distances[b] = 2"
"b = 3"

为什么迭代不继续在这里a=2: b=4?

Why doesn't the iteration continue to a=2: b=4 here?

"a = 3: b = 4"
"distances[a] = 2, distances[b] = 18"
"a = 3: b = 5"
"distances[a] = 2, distances[b] = "
"a = 3: b = 6"
"distances[a] = 2, distances[b] = 7"
"nearest_vertex = 3"
...

一旦a设置为3,一切都会按我认为的方式工作.程序如何知道nearest_vertex是三?

Once a is set to 3, everything works as I thought it should. How does the program know that nearest_vertex is three?

在确定如何以及何时将顶点声明为nearest_vertex时,我不理解injectnext之间的相互作用.没有比较运算符时如何比较距离?

I don't understand the interaction between inject and next in determining how and when to declare a vertex to be the nearest_vertex. How are the distances compared when there is no comparison operator?

推荐答案

让我用纯Ruby解释Enumerable#inject.请注意,以下代码的原始实现.为了清楚起见,我将在类Array中对其进行解释,并重点介绍最基本的用法ary.inject(&block):

Let me explain Enumerable#inject in pure Ruby. Note that the following code is NOT the original implementation of Enumerable#inject. For clarity, I will explain it in class Array, and focus on the most basic usage ary.inject(&block):

class Array
  def inject(&block)
    return nil if self.empty?

    enumerator = self.each

    accumulator = enumerator.next

    loop do
      begin
        accumulator = block.call(accumulator, enumerator.next)
      rescue StopIteration
        break
      end
    end

    accumulator
  end
end

您可以看到在循环中,先前迭代的累加器和数组的当前元素被传递给块的参数,并且块的返回值被重新分配给累加器.

You can see that in the loop, the accumulator of previous iteration and the current element of the array is passed to the block's params, and the block's return value is reassigned to the accumulator.

那么什么是next x块?

您可以将块视为一个匿名函数,而关键字next是其return.它将终止当前的块调用,并使该块返回x(如果未显式指定返回值,则返回nil).

You can think of a block as an anonymous function, and the keyword next is its return. It terminates the current block call and makes the block return x (nil if the return value is not explicitly specified).

顺便说一句,块中的break x终止占用该块的方法调用,并使该方法返回x.例如:

By the way, break x in a block terminates the method call which takes the block, and makes the method return x. For example:

[1, 2, 3, 4].inject do |acc, n|
   break n if n == 2
   acc + n
end
=> 2

n2时,Array#injectbreak终止,并返回n.

The Array#inject is terminated by the break when n is 2, and that n is returned.

return终止调用该块的方法的方法调用.例如:

return in a block terminates the method call which calls the method that takes the block. For example:

def foo
  [1, 2, 3].inject do |acc, n|
    return n
  end
  puts 'You will never see this this sentence.'
end

foo
=> 2

并且没有打印句子,因为fooreturn结尾.

And there is no sentence printed, because foo is terminated by return.

这篇关于使用“注入",“除非"和“下一个"来确定最小值的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆