【问题标题】:Array sort is not working correctly in JavaScript [duplicate]数组排序在 JavaScript 中无法正常工作 [重复]
【发布时间】:2023-10-18 22:58:01
【问题描述】:

我试过这个代码

function sort() {
    var ary = [2, 1, 0.4, 2, 0.4, 0.2, 1.5, 1, 1.1, 1.3, 1.2, 0.2, 0.4, 0.9];
    alert(ary.sort(function(a, b) {return a < b;}));
}
sort();

但结果是

[1, 2, 2, 1.1, 0.9, 1.2, 1.5, 1, 1.3, 0.4, 0.4, 0.4, 0.2, 0.2]

如果数组的长度很短,它可以工作。但它不适用于长数组。 谢谢。

【问题讨论】:

  • 您可以将其缩短为return ary.sort((a,b) =&gt; a &lt; b);
  • 抱歉,误会了。请尝试编辑一个。
  • 试试function(a, b) {return a - b;}
  • @SterlingArcher Array.prototype.sort() 期望返回整数,而不是布尔值;)
  • @Archer 打得好,我更关注语法而不是排序问题,哈哈

标签: javascript arrays json


【解决方案1】:

您的排序失败,因为您的比较函数不符合specifications for Array.sort

  • 如果 compareFunction(a, b) 小于 0,则将 a 排序到低于 b 的索引,即 a 排在第一位。
  • 如果 compareFunction(a, b) 返回 0,则 a 和 b 彼此保持不变,但对所有不同元素进行排序。注意:ECMAscript 标准不保证这种行为,因此并非所有浏览器(例如,至少可以追溯到 2003 年的 Mozilla 版本)都尊重这一点。
  • 如果 compareFunction(a, b) 大于 0,则将 b 排序到低于 a 的索引,即 b 排在第一位。
  • compareFunction(a, b) 在给定一对特定元素 a 和 b 作为其两个参数时,必须始终返回相同的值。如果返回不一致的结果,则排序顺序未定义。

您的比较函数返回一个布尔值,实际上只返回值 0 和 1。您应该根据 David's answer 中的规范修复比较函数。下面是一个简单的比较函数1

var ary = [2, 1, 0.4, 2, 0.4, 0.2, 1.5, 1, 1.1, 1.3, 1.2, 0.2, 0.4, 0.9];
console.log(ary.sort(compareDecimals));

function compareDecimals(a, b) {
    if (a === b) 
         return 0;

    return a < b ? -1 : 1;
}

其他答案(使用function { return a - b; }利用数学巧合。即相等的值有0的差异。这适用于“正常”值,但是当您的数据包含Inifinity之类的值时很容易出错或Number.MIN_SAFE_INTEGER


1.如 cmets 中所述,此函数不能解决所有疯狂的 javascript 数字行为,例如 NaN === NaN 的计算结果为 false。同样用于处理混合类型的数组。根据数据的性质,根据需要设计比较函数。

【讨论】:

  • 第一个例子也可能失败,因为 NaN 是一个数字。只是说。
  • @SalmanA 谢谢。我在脚注中指出了这一点,因为它并不是核心问题的真正重点,而是关于 array.sort 的实际工作方式。
  • @ryanyuyu,感谢您提出这个问题。 InfinityNumber.MIN_SAFE_INTEGER 使用默认排序方法。 Infinity 在内存中与 Number.MIN_SAFE_VALUE 一起表示为一个值,因此如果将它们添加到数组中(使用默认行为),它们将相应地排序。
  • 我还要说 NaN 与默认的 sort 函数一起工作(总是在数组的末尾),但是在这个比较函数中,NaN 会导致排序出错。输出:var ary = [2, 1, 0.4, 2, 0.4, 0.2, 1.5, 1, 1.1, 1.3, 1.2, 0.2, 0.4, 0.9, Infinity, Number.MIN_SAFE_INTEGER, NaN]; console.log(ary.sort(compareDecimals));函数 compareDecimals(a, b) { if (a === b) 返回 0;返回 a
  • 另外,请考虑 JS 数学不精确的事实。见*.com/questions/5153061/…
【解决方案2】:

已编辑附加信息:

我很抱歉,但这个问题的最短答案是:

function sort() {
    var ary = [2, 1, 0.4, 2, 0.4, 0.2, 1.5, 1, 1.1, 1.3, 1.2, 0.2, 0.4, 0.9];
    // use custom compare function that sorts numbers ascending
    alert(ary.sort(function(a, b) {
        return a - b;
    }));
}

sort();

请注意,如果没有为sort 方法提供比较函数,则通过将元素转换为字符串并以Unicode 代码点顺序比较字符串来对元素进行排序。所以[1, 2, 10].sort() 产生[1, 10, 2] 因为"10" 作为一个字符串出现在"2" 之前。上面的代码会正确返回从小到大排序的数组。

您可以通过在 return 语句中颠倒 a 和 b 来对从大到小进行排序(降序):

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

【讨论】:

  • 这是错误的。默认情况下,数组将被排序为字符串。
  • 一个快速反例:[9, 99, 901].sort() 返回[9, 901, 99],这显然不是按数字顺序排列的。
  • 发布编辑并更新了有关为什么会发生这种情况的其他信息。谢谢。
  • 对不起,default 行为还是有问题的。
  • 请让我知道我哪里错了。但是直接引用MDN 文章中的sort 方法:“如果没有提供 compareFunction,则通过将元素转换为字符串并以 Unicode 代码点顺序比较字符串来对元素进行排序。”
【解决方案3】:

试试:

var ary = [2, 1, 0.4, 2, 0.4, 0.2, 1.5, 1, 1.1, 1.3, 1.2, 0.2, 0.4, 0.9];

function compare(a, b) {
    if (a < b) {
        return -1;
    } else if (a > b) {
        return 1;
    } else {
        return 0;
    }
}


ary = ary.sort(compare);
alert(ary);

【讨论】:

  • 为什么不把它简化为function compare(a, b) { return a - b }
  • 啊,是的,这是有道理的:P
  • 不一样,因为JS浮点数学不精确,所以a - b最终可能不等于0。
  • @Matthias:它们并不精确,但如果a === b 那么a - b === 0
  • @cpcallen 啊,你是对的! MDN 还声明返回值可以是任何负数/正数,所以a - b 完全没问题!
【解决方案4】:

您的代码在警报中有错字。

无论如何正确的实现是 -

function sort() {
        var ary = [2, 1, 0.4, 2, 0.4, 0.2, 1.5, 1, 1.1, 1.3, 1.2, 0.2, 0.4, 0.9];
        return ary.sort(function(a, b) {return a - b;});
}
    
alert(sort());

输出 - [0.2, 0.2, 0.4, 0.4, 0.4, 0.9, 1, 1, 1.1, 1.2, 1.3, 1.5, 2, 2]

(使用 b - a 更改排序顺序)。

【讨论】:

  • 这工作得很好......谢谢