【问题标题】:How does sort function work in JavaScript, along with compare function排序函数在 JavaScript 中如何工作,以及比较函数
【发布时间】:2011-09-27 22:01:47
【问题描述】:

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

【问题讨论】:

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

标签: javascript


【解决方案1】:

我们可以简化以正常顺序逆序

的排序

第一个参数a

第二个参数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;  
}

【讨论】:

    【解决方案2】:

    此时可以使用 Uint32Array 来创建数组。

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

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

    【讨论】:

      【解决方案3】:

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

      ex1 :strings

      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 . 
      

      【讨论】:

        【解决方案4】:

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

        1. 如果 a 大于 b,则返回大于 0
        2. 如果 a 等于 b,则返回 0
        3. 如果 a 小于 b,则返回小于 0

        有了这三个返回值,并且只有两个参数,就可以编写一个比较函数来对任何类型的输入数据类型或复杂的数据结构进行排序。

        然后,当您使用自定义比较函数调用 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 谢谢你,它有帮助。
        【解决方案5】:

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

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

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

        【讨论】:

          【解决方案6】:

          我觉得可能是这样的(嗯,这个我也不确定):

          假设函数compare(a,b) 是比较函数。 它返回c。 假设我们要对数组N中的条目进行排序,得到排序结果数组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 语言规范说结果应该有这个属性: (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)

          【讨论】:

            【解决方案7】:

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

            你传入的函数有两个参数,通常称为 a 和 b,并返回: 如果第一个参数应该排在第二个之前,则为负数 (a b)

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

            你的函数可以有一个if / else if / else 结构来决定返回什么结果,但是对于数字来说,简单地返回 (ab) 将为你实现这一点,因为减法的结果将是 -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 的示例。
            • 我喜欢'sort() 将被重复调用' +1 的描述
            • 因此,在对数字进行排序时,我可以返回 -1、0、1 或者我可以返回 b - aa - b。结果会是一样的,是吗?在这种情况下,-11 没有显着差异或有什么特别之处?
            • @VisWebsoft - 是的,结果是一样的。
            猜你喜欢
            • 2022-11-16
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2019-03-25
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多