1

我理解#max、#min、#minmax。我理解<=>。但它是如何在其中一个函数中的一个块中工作的呢?

也就是说,下面第三行发生了什么?#min <=> 在做什么?

a = %w(albatross dog horse)
a.min                                   #=> "albatross"
a.min { |a, b| a.length <=> b.length }  #=> "dog"

来自http://ruby-doc.org/core-2.2.3/Enumerable.html#method-i-min的示例

它对一组数字有什么行为?

4

2 回答 2

4

正如您可能已经看到的那样,该方法的文档min说:

min(n) → array

min(n) {| a,b | block } → array

返回枚举中具有最小值的对象。第一种形式假设所有对象都实现Comparable;第二个使用块返回a <=> b

这意味着,在第一种形式中,min调用<=>数组中对象的方法并使用结果来确定哪个元素是最小的。

在第二种形式中,使用它要比较的两个元素min调用块,并使用块的返回值来确定哪个元素是最小的。基本上,它使用块就好像它是<=>运算符的实现一样。所以x.min {|a,b| a <=> b }将相当于x.min.

在给出的示例 ( a.min { |a, b| a.length <=> b.length } #=> "dog") 中,这意味着不是比较每个元素来确定排序顺序,而是比较每个元素的长度来做出决定。由于"dog"是列表中最短的字符串,因此它是由 . 返回的值minmax, minmax, 并且sort行为相似。

请注意,该示例有点做作,因为您可以min_by在这种情况下使用更简单的代码来实现相同的结果a.min_by { |x| x.length }:如果您在确定排序顺序时想要更细粒度的控制,则使用min块可能是合适的。

它对一组数字有什么行为?

min无论数组包含什么,其行为方式都相同。在这种情况下,虽然使用块{ |a, b| a.length <=> b.length }不起作用,因为数字没有length方法。这是一个更好的数字示例,它按从小到大排序,但始终将奇数视为大于偶数:

[2, 10, 9, 7, 6, 1, 5, 3, 8, 4].sort do |a, b|
  if a.odd? && b.even?
    1
  elsif a.even? && b.odd?
    -1
  else
    a <=> b
  end
end

结果:

[2, 4, 6, 8, 10, 1, 3, 5, 7, 9]

请注意在最终数组中偶数如何排在奇数之前?这是我们传递给的块的结果sortminmax和的行为类似minmax

于 2015-09-04T20:39:16.120 回答
2

min将两个元素ab从数组传递到块,块预计返回-1, 0, 或+1取决于是否a小于、等于或大于b。"spaceship" 运算符<=>返回这些-10+1值。

算法很简单。给定一个比较函数:

cmp = -> (a, b) { a.length <=> b.length }

我们首先比较第一个和第二个元素:

cmp.call 'albatros', 'dog'
#=> 1

1均值'albatros'大于'dog'。我们继续使用较小的值,'dog'即将它与第三个元素进行比较:

cmp.call 'dog', 'horse'
#=> -1

-1均值'dog'小于'horse'。没有更多'dog'的元素,结果也是如此。

你也可以在 Ruby 中实现这个算法:

def my_min(ary)
  ary.inject { |min, x| yield(x, min) == -1 ? x : min }
end

ary = %w(albatross dog horse)
my_min(ary) { |a, b| a.length <=> b.length }
#=> "dog"
于 2015-09-04T21:36:44.337 回答