在深入研究数组方法时,我决定看一下Array.sort方法中涉及的步骤。看一下下面的代码,以反转数组的顺序:
let arr = [];
for (let i = 1; i < 6; i++) {
arr.push(i);
}
arr.sort((value1, value2) => {
console.log(arr);
console.log(`Comparing ${value1} : ${value2}`);
return value2 - value1;
});
console.log(arr);
我得到以下输出:
[1, 2, 3, 4, 5]
Comparing 1 : 2
[2, 1, 3, 4, 5]
Comparing 1 : 3
[2, 1, 1, 4, 5]
Comparing 2 : 3
[3, 2, 1, 4, 5]
Comparing 1 : 4
[3, 2, 1, 1, 5]
Comparing 2 : 4
[3, 2, 2, 1, 5]
Comparing 3 : 4
[4, 3, 2, 1, 5]
Comparing 1 : 5
[4, 3, 2, 1, 1]
Comparing 2 : 5
[4, 3, 2, 2, 1]
Comparing 3 : 5
[4, 3, 3, 2, 1]
Comparing 4 : 5
[5, 4, 3, 2, 1]
前两步很有意义,但请看第三步:[2, 1, 1, 4, 5]
。
为什么我期望[2, 3, 1, 4, 5]
时会出现这种情况?
正如您可以看到的那样,这种重复的数字现象一次又一次地出现,直到阵列最终反转为止。我想念什么?显然,每次突变后,arr
中不在的某个地方都会保留数组的副本。
答案 0 :(得分:3)
当数组是小型浏览器时(嗯...至少chrome,safari和node)使用插入排序。您看到的行为是在插入排序循环中间查看数组的结果。您可以使用以下方式重现它:
let arr = [ 1, 2, 3, 4, 5];
function InsertionSort(a, comparefn) {
let from = 0
let to = a.length
for (var i = from + 1; i < to; i++) {
var element = a[i];
for (var j = i - 1; j >= from; j--) {
var tmp = a[j];
var order = comparefn(tmp, element); //<-- your console.log is peaking at the array here
if (order > 0) {
a[j + 1] = tmp;
} else {
break;
}
}
a[j + 1] = element;
}
};
InsertionSort(arr, (a,b) => {
console.log(arr.join(","))
return b-a
})
console.log(arr)
请记住,这不是必需的实现,因此您不必指望这种行为。
答案 1 :(得分:1)
添加到@ mark-meyer答案。对于浏览器,没有关于如何基于提供给sort
方法的回调来比较数字的规范。
例如,Array.sort()
有时用于通过以下方式均匀地随机化阵列:
var shuffledArr = arr.sort(() => (Math.random() - 0.5))
在这种情况下
如果comparefn不是未定义的,并且不是该数组元素的一致比较函数(请参见下文),则排序顺序是实现定义的。
https://www.ecma-international.org/ecma-262/6.0/#sec-array.prototype.sort
您可以检查此页以在浏览器内查看随机化结果:http://siri0n.github.io/attic/shuffle-comparison/index.html。比较Chrome和Firefox。不仅如此,Firefox将为不同的字段大小选择不同的排序算法。不是答案,但我希望对这个问题有一个有趣的补充。
答案 2 :(得分:-1)
感谢提出了一个令人惊讶的有趣问题。
有副作用/后果:如果异常发生在比较器回调数组内部,则可以打破(不仅是部分排序):
let a = [1, 3, 2, 6, 4];
let stepToFail = 2;
try {
a.sort((x1, x2) => {
if (!stepToFail--) throw "test";
return x1 - x2;
});
} catch(e) {
// shows [1,3,3,6,4] in Chrome; data is broken and cannot be used anymore
console.log(JSON.stringify(a));
}
[UPD]我在Chromium项目中报告了a bug,并且由于“无法修复”而被关闭
Array.prototype.sort在Chrome 70.0.3533中重新实现。那是 行为发生变化的原因。
不管发生什么变化,上面的示例并没有真正 构成一个错误。比较功能不“一致”,并且 根据规范,最终的排序顺序是实现定义的。那 包含“不一致状态”,因为可以在 寻找合适的位置放置值或在将其写入之前 回来。