【问题标题】:How does sort function work in JavaScript, along with compare function排序函数如何在 JavaScript 中工作,以及比较函数
【发布时间】:2022-11-16 09:46:04
【问题描述】:

正如已经问到的那样:sort 函数如何与 compare 函数一起在 JavaScript 中工作? 如果我有一个数组,我现在做array.sort(compare),书中写道,如果compare函数返回a-b(数组的两个索引),那么它的工作基于结果是否更大的事实小于 0、小于 0 或等于 0。但是,它究竟是如何工作的呢?我无法解决。

【问题讨论】:

  • 你到底需要知道什么?我很确定所使用的排序算法是特定于实现的。
  • 比较函数与排序功能有什么关系,它不会只是比较两个变量并将这两个变量的结果返回给我,整个数组如何排序?

标签: javascript


【解决方案1】:

“比较”函数必须有两个参数,通常称为一个b.然后根据这些值让比较函数返回 0、大于 0 或小于 0,一个b.

  1. 返回大于 0 如果一个大于b
  2. 返回 0 如果一个等于b
  3. 返回小于 0 如果一个小于b

    使用这三个返回值和两个参数,可以编写一个可以对任何类型的输入数据类型或复杂数据结构进行排序的比较函数。

    然后,当您使用自定义比较函数调用 sort() 时,将对待排序列表中的对调用比较函数,以确定正确的顺序。

    让我们看一个简单的例子......假设你只是对一些数字进行排序,所以我们有一个非常简单的比较函数:

    function compare(a,b) {
        return a - b;
    }
    

    如果 a 大于 b,则简单地从 a 中减去 b 将始终返回大于零,如果它们相等,则返回 0,如果 a 小于 b,则返回小于零。所以它满足比较功能的要求。

    现在假设这是我们要排序的数字列表:

    var numbers = [1,5,3.14];
    

    当你调用numbers.sort(compare)时,在内部它实际上会执行:

    compare(1,5);     // Returns -4, a is less than b
    compare(1,3.14);  // Return -2.14, a is less than b
    compare(5,3.14);  // returns 1.86, a is greater than b
    

    如果您曾经进行过手动排序或按字母顺序排序,那么您可能已经做过完全相同的事情,但可能没有意识到。即使您可能有几十个或数百个项目要比较,您也经常一次只比较两个数字(或作者的姓氏,或其他)。再次查看三个数字的短列表,您将从比较前两个数字开始:

    1. 1 是大于还是小于 5?小于,所以将这两个数字放入我们的列表中:1,5
    2. 3.14 是大于还是小于 1?大于,所以它在新列表中排在 1 之后
    3. 在我们的新列表中,3.14 是大于还是小于 5?小于,所以它在 5 之前。我们的新列表现在是 [1,3.14,5]

      因为您可以提供自己的 compare() 函数,所以可以对任意复杂的数据进行排序,而不仅仅是数字。

【讨论】:

  • 上述情况下的时间复杂度如何?
  • 每个函数都有时间复杂度。我很确定 javascript .sort() 使用快速排序 (n log n ),但他通过调用辅助函数 compare(a,b) 询问将添加多少。我会说,因为比较是线性的,函数仍然保持渐近行为。如果有人能证实这一点,那就太好了!
  • 那么,我们是否应该在对任何东西进行排序之前自己声明比较函数,否则 sort() 方法如何知道我们正在使用哪个比较函数?
  • @FadeocKhaos 当您执行 number.sort(a, b) 时(如上例所示),您将比较函数作为参数传递给 sort()。 JavaScript 数组中的 sort() 接受比较 fn 作为可选参数。由于比较 fn 在这种情况下仅充当参考,因此它充当匿名函数。这本身就是一个更广泛的话题,但我希望这会有所帮助。如果作为单独的问题发布,我可以为您提供详细信息。谢谢。
  • @ranjith 谢谢你,它有帮助。
【解决方案2】:

默认情况下,数组 sort() 方法按字母升序排序。如果你想按其他顺序排序,因为你的数组包含数字或对象,那么你可以将函数传递给 sort()

您传入的函数有两个参数,通常称为 a 和 b,并返回: 如果第一个参数应该排在第二个之前,则为负数 (a < b) 0 如果参数相等 (a==b) 如果第一个参数应排在第二个参数 (a > b) 之后,则为正数

现在,这是关键位:您作为参数传递给sort() 的函数将在处理整个数组时被sort() 重复调用。 sort() 不知道或不关心数组中事物的数据类型:每次它需要知道“项目 A 在项目 B 之前吗?”它只是调用你的函数。您无需担心 sort() 在内部使用何种类型的排序算法,实际上一个浏览器可能使用与另一个浏览器不同的算法,但这没关系,因为您只需要提供一种方法来比较任何两个项目从你的阵列。

您的函数可以有一个 if / else if / else 结构来决定返回什么结果,但是对于数字,简单地返回 (a-b) 将为您实现这一点,因为减法的结果将是 -ve、0 或 +ve 并正确地将数字放入升序。返回 (b-a) 会使它们下降:

  var sortedArray = myArray.sort(function(a,b){
                                    return (a-b);
                                });

如果您有一个对象数组并且想要对对象的某个或多个特定属性进行排序,您也可以这样做。假设,例如,这种格式的对象:

{ id : 1,
  name : "Fred",
  address : "12 Smith St",
  phone : "0262626262" }

然后,您可以按“id”属性对此类对象的数组进行排序,如下所示:

var sortedArray = myArray.sort(function(a,b){
                                  return (a.id - b.id);
                              });

或者您可以按“名称”属性(按字母顺序)对此类对象的数组进行排序,如下所示:

var sortedArray = myArray.sort(function(a,b){
                                   if (a.name < b.name)
                                      return -1;
                                   else if (a.name == b.name)
                                      return 0;
                                   else
                                      return 1;
                               });

请注意,在我的最后一个示例中,我放置了前面提到的完整的 if / else if / else 结构。

对于您正在对具有多个属性的对象进行排序的示例,您可以进一步扩展以包括二次排序,也就是说,(在我的示例中)如果名称属性相等,则您可以返回电话属性的比较。

【讨论】:

  • 我更喜欢这个答案,因为它包含一个字符串比较 +1 的示例。
  • 我喜欢'排序()将被重复调用'的描述+1
  • 因此,在对数字进行排序时,我可以返回 -1、0、1 或者我可以返回 b - aa - b。结果会一样,不是吗?在这种情况下,-11 没有显着差异或有什么特别之处吗?
  • @VisWebsoft - 是的,结果是一样的。
【解决方案3】:

该方法使用Array.sort(compareFunction sortOptions)的语法和参数排序,其参数定义如下:

compareFunction - 用于确定数组元素排序顺序的比较函数。此参数是可选的。应该使用比较函数来比较两个参数。给定元素的 A 和 B,compareFunction 的结果可以有负值、0 或正值:

如果返回值为负数,则表示在排序序列中 A 出现在 B 之前。 如果返回值为 0,则 A 和 B 的排序顺序相同。 如果返回值为正数,则表示在排序后的序列中,A 出现在 B 之后。

【解决方案4】:

我们可以简化排序正常顺序相反的顺序

第一个参数一个.

第二个参数b.

function compare(a, b) {
  //  make some operations to calculate these variables as true or false
  //     weNeedToMoveFirstParameterInPositiveDirection
  //     weDoNotNeedToMove
  //     weNeedToMoveFirstParameterInNegativeDirection

  // just think about numerical axis <------(-1)---(0)---(1)------>
  if (weNeedToMoveFirstParameterInPositiveDirection) return 1;  
  if (weDoNotNeedToMove) return 0; 
  if (weNeedToMoveFirstParameterInNegativeDirection) return -1;  
}

【讨论】:

  • 为什么人们对此评论不多?很高兴记住比较器结果将如何影响结果
  • 同意 Rohit,这是一个聪明而有用的解释
【解决方案5】:

sort 方法单独将数字视为字符串,因此如果字符串数组则不需要比较函数。 但是如果是数字数组,则需要比较函数来更改排序方法的构建行为。

ex1:字符串

var animals = ["Horse", "Cat", "Tiger", "Lion"];  
animals.sort();

ex2 : 数字

var marks = [70, 90, 60, 80 ];  
marks.sort(function(a, b){return a > b}); //ascending , a < b descending . 

【讨论】:

    【解决方案6】:

    您现在可以使用 Uint32Array 来创建数组。

    [https://i.stack.imgur.com/qBgvm.png]

    但是,它有一些困难。例如,您不能向数组添加新值。简单地说,您不能修改数组长度。

    【讨论】:

      【解决方案7】:

      我觉得可能是这样的(好吧,我不太确定):

      假设函数compare(a,b) 是比较函数。 它返回c。 假设我们要对arrayN中的条目进行排序,得到排序结果数组M

      我不知道确切的排序算法,如果c既不是(a-b)也不是(b-a)(比如,如果c"b-2""a+b"或其他一些表达式),不同的浏览器甚至会返回不同的结果.

      但是根据ECMA-262,排序结果应该是这样的:

      a , b 可以是索引中的任意两个。 这意味着我们实际上将一个有序对传递给比较函数。 eg: (0,1),(1,4), or even (2,0) , (2,1)

      ECMAScript Language Specification 说结果应该有这个属性: (a,b)是传递给比较函数的有序对。

      • 如果c(函数返回的内容)小于零,则必须满足M(a)&lt; M(b)

      并且规范没有提及如果 c 为零或大于零会发生什么。

      我不确定这是否正确。 至少这可以很容易地解释为什么当c"a-b"时,条目被排序为数字和升序,以及为什么当c"b-a"时,条目被排序为相反。

      浏览器的 js 引擎是不是真的严格按照 ECMA-262 设计的,还是我完全错了?

      参考:

      The Fifth Edition of ECMA-262 (Check page 129-130)

      【讨论】:

        猜你喜欢
        • 2011-09-27
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-03-25
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多