当块传递时,Array#sort如何工作?

时间:2010-04-14 12:47:57

标签: arrays ruby sorting

我在理解array.sort{ |x,y| block }如何正常工作时遇到问题,因此如何使用它?

来自Ruby documentation的示例:

   a = [ "d", "a", "e", "c", "b" ]
   a.sort                     #=> ["a", "b", "c", "d", "e"]
   a.sort { |x,y| y <=> x }   #=> ["e", "d", "c", "b", "a"]

7 个答案:

答案 0 :(得分:121)

在你的例子中

a.sort

相当于

a.sort { |x, y| x <=> y }

如您所知,要对数组进行排序,您需要能够比较其元素(如果您对此有疑问,只需尝试实现任何排序算法而不使用任何比较,不<,{{1} },><=)。

您提供的块实际上是一个函数,>=算法将调用该函数来比较两个项目。 sortx始终是y算法在执行期间选择的输入数组的一些元素。

sort算法将假设此比较函数/块将满足方法sort的要求:

  • 如果x&lt;则返回-1。 ÿ
  • 如果x = y
  • 则返回0 如果x&gt;
  • 返回1 ÿ

未能提供足够的比较函数/块将导致数组的顺序未定义。

你现在应该明白为什么

<=>

a.sort { |x, y| x <=> y }

以相反的顺序返回相同的数组。


详细说明Tate Johnson添加的内容,如果您在任何课程上实施比较功能a.sort { |x, y| y <=> x } ,您将获得以下内容

  1. 您可以在课程中加入<=>模块,该模块会自动为您定义以下方法:Comparablebetween?==>=<<=
  2. 现在可以使用默认(即无参数)调用>对您的类的实例进行排序。
  3. 请注意,在ruby的标准库中sort<=>BignumArray,{{ 1}},File::Stat等等......)。

答案 1 :(得分:21)

当你有一个数组,比如整数排序时,sort方法正确地排序元素是非常简单的 - 首先是较小的数字,最后是较大的数字。那是你使用普通的sort,没有阻止。

但是当你对其他对象进行排序时,可能需要提供一种比较(每个)两个对象的方法。假设你有一个类Person的对象数组。您可能无法判断对象bob是否大于对象mike(即,类Person没有实现方法<=>。在这种情况下,您需要提供一些代码来解释您希望将这些对象排序为sort方法的顺序。这就是阻止形成的地方。

people.sort{|p1,p2| p1.age <=> p2.age}
people.sort{|p1,p2| p1.children.count <=> p2.children.count}

等。在所有这些情况下,sort方法以相同的方式对它们进行排序 - 使用相同的算法。不同的是比较逻辑。

答案 2 :(得分:8)

@OscarRyz回复在关于排序如何运作的问题上为我清理了很多,特别是

 { |x, y| y <=> x }

根据我的理解,我在这里提供了在上述块结果的每次比较之后数组的状态。

注意:得到了打印块参数e1,e2的值的参考 ruby-forum

1.9.3dev :001 > a = %w(d e a w f k)
1.9.3dev :003 > a.sort { |e1, e2| p [e2, e1]; e2 <=> e1 }
["w", "d"]
["k", "w"]
["k", "d"]
["k", "e"]
["k", "f"]
["k", "a"]
["f", "a"]
["d", "f"]
["d", "a"]
["d", "e"]
["e", "f"]
 => ["w", "k", "f", "e", "d", "a"]

每次比较后运行时猜测的数组状态:

 [e2, e1]    Comparsion Result       Array State
["w", "d"]      1                   ["w", "e", "a", "d", "f", "k"]
["k", "w"]     -1                   ["w", "e", "a", "d", "f", "k"]
["k", "d"]      1                   ["w", "e", "a", "k", "f", "d"]
["k", "e"]      1                   ["w", "k", "a", "e", "f", "d"]  
["k", "f"]      1                   ["w", "k", "a", "e", "f", "d"]    
["k", "a"]      1                   ["w", "k", "a", "e", "f", "d"]  
["f", "a"]      1                   ["w", "k", "f", "e", "a", "d"]  
["d", "f"]     -1                   ["w", "k", "f", "e", "a", "d"]  
["d", "a"]      1                   ["w", "k", "f", "e", "d", "a"]  
["d", "e"]     -1                   ["w", "k", "f", "e", "d", "a"]  
["e", "f"]     -1                   ["w", "k", "f", "e", "d", "a"] (Result)

谢谢,

Jignesh

答案 3 :(得分:7)

<=>是返回(self.<=>( argument )

的ruby方法
  • -1如果自己&lt;论点
  • 0 if self == argument
  • 1 if self&gt;参数

xy是数组项。如果没有提供阻止,则sort函数使用x<=>y,否则阻塞的结果表示x应该在y之前。

array.sort{|x, y| some_very_complicated_method(x, y) }

这里,如果some_very_complicated_method(x,y)返回的smth是&lt; 0,x被认为是&lt;比y等......

答案 4 :(得分:4)

一些杂项:

  • xy称为块参数。排序方法基本上说“我会给你x和y,你确定x或y是否应该先排序,我会照看关于排序的无聊的东西”
  • <=>被称为spaceship operator

答案 5 :(得分:3)

在:

a.sort {|x,y| y <=> x }   #=> ["e", "d", "c", "b", "a"]
  

什么是x和y?

xy是排序算法进行比较的元素。

这对于定义哪个元素应该在另一个之前的自定义类很有用。

对于基本数据(数字,字符串,日期等),自然顺序是预定义的,但对于客户元素(即员工),您可以定义谁在比较之前。这个块让你有机会定义它。

  

以及在y&lt; =&gt; x?

时会发生什么

在那里,他们正在按降序比较元素(具有“更高”值的元素将首先)而不是自然顺序(x<=>y

<=>方法代表“compareTo”,如果元素相同,则返回0;如果<xy更早,则返回> 0如果xy

之后,则为0

答案 6 :(得分:2)

我相信| x,y | y&lt; =&gt; x按降序一次比较两个元素,如下所示: http://www.ruby-doc.org/core-1.9.3/Array.html#method-i-3C-3D-3E 用[“d”,“a”,“e”,“c”,“b”],“d”和“a”说似乎首先进行比较。然后因为它是下降的,所以两者都保持相同的顺序,因为d的计算结果小于a。然后评估d和e。 “e”移动到“d”的位置。在不知道c代码的内部工作原理的情况下,不可能知道d移动到哪里,但我认为这个过程一直持续到所有元素都被排序。 c函数:

           VALUE
rb_ary_cmp(VALUE ary1, VALUE ary2)
{
    long len;
    VALUE v;

    ary2 = rb_check_array_type(ary2);
    if (NIL_P(ary2)) return Qnil;
    if (ary1 == ary2) return INT2FIX(0);
    v = rb_exec_recursive_paired(recursive_cmp, ary1, ary2, ary2);
    if (v != Qundef) return v;
    len = RARRAY_LEN(ary1) - RARRAY_LEN(ary2);
    if (len == 0) return INT2FIX(0);
    if (len > 0) return INT2FIX(1);
    return INT2FIX(-1);
}