【问题标题】:Ruby combined comparison operator (<=>) and min / max / minmax functionsRuby 组合比较运算符 (<=>) 和 min / max / minmax 函数
【发布时间】:2015-09-04 20:29:44
【问题描述】:

我了解#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的示例

对于一个数字数组会有什么行为?

【问题讨论】:

    标签: ruby max min logical-operators minmax


    【解决方案1】:

    您可能已经看到,the documentationmin 方法说:

    min(n) → array

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

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

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

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

    在给出的示例 (a.min { |a, b| a.length &lt;=&gt; b.length } #=&gt; "dog") 中,这意味着不是比较每个元素来确定排序顺序,而是比较每个元素的 长度 来确定。由于"dog" 是列表中最短的字符串,这就是min 返回的值。 maxminmaxsort 的行为类似。

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

    对于数字数组会有什么行为?

    min 的行为方式相同,无论数组包含什么。在这种情况下,尽管使用块 { |a, b| a.length &lt;=&gt; 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]
    

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

    【讨论】:

    • 好答案。如果插入puts "a=#{a}, b=#{b}",将打印以下内容:"a=dog, b=albatross" 然后"a=horse, b=dog"。实际上,min 首先假设 "dog" 将成为获胜者,然后执行成对比较,到目前为止,b 始终指的是获胜者。
    【解决方案2】:

    min 将数组中的两个元素 ab 传递给块,根据 a 是否小于,等于或大于b。 “宇宙飞船”运算符 &lt;=&gt; 返回这些 -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"
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-08-25
      • 1970-01-01
      • 1970-01-01
      • 2012-07-25
      • 2016-03-22
      • 2021-11-26
      • 2017-08-06
      • 2011-03-10
      相关资源
      最近更新 更多