ChatGPT解决这个技术问题 Extra ChatGPT

如何在不改变原始数组的情况下对数组进行排序?

假设我想要一个排序函数,它返回输入数组的排序副本。我天真地尝试了这个

function sort(arr) {
  return arr.sort();
}

我对此进行了测试,这表明我的 sort 方法正在改变数组。

var a = [2,3,7,5,3,7,1,3,4];
sort(a);
alert(a);  //alerts "1,2,3,3,3,4,5,7,7"

我也尝试过这种方法

function sort(arr) {
  return Array.prototype.sort(arr);
}

但它根本不起作用。

有没有一种直接的方法来解决这个问题,最好是一种不需要手动滚动我自己的排序算法或将数组的每个元素复制到新元素中的方法?

创建数组的深层副本并对其进行排序。
@evanmcdonnal 如果只需要重新排序而不是数组中每个项目的副本,那么浅拷贝可能就足够了。
.sort 要求 this 值是数组,因此要使最后一个代码段起作用,您需要执行 .sort.call(arr)(尽管它不能解决您的问题)。
@Kekoa 是的,这是一个很好的观点。如果您只想更改元素的顺序而不是元素本身,则无需消耗更多内存。
zzzzBov 的方法很有魅力! stackoverflow.com/a/9592774/7011860

P
Putzi San

您需要先复制数组,然后再对其进行排序。 es6的一种方法:

const sorted = [...arr].sort();

作为数组文字的扩展语法(从 mdn 复制):

var arr = [1, 2, 3];
var arr2 = [...arr]; // like arr.slice()

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_operator


这真的很棒。我认为比 concat 和其他方法更容易理解
这段代码确实有效,但是当我用 Gulp 编译 JS 时,它返回一个错误,SyntaxError: Unexpected token: punc (.)
对于那些说它不是有效的 JavaScript 的人......它是完全有效的。如果您使用的是 Chrome/Safari/Edge 或 Firefox:打开开发控制台,定义一个名为 arr 的数组并粘贴表达式以查看结果。
@Cerin 听起来您使用的是非常过时的 JS 版本。
此方法是否比 .slice() 更快地获取数组的副本?
R
Rob W

只需复制数组。有很多方法可以做到这一点:

function sort(arr) {
  return arr.concat().sort();
}

// Or:
return Array.prototype.slice.call(arr).sort(); // For array-like objects

这是否会进行深度复制,即嵌套对象和数组也会被复制吗?
使用 concat 比使用 slice(0) 有什么优势,还是它们几乎都一样?
@PeterOlson 不,这是一个浅拷贝。如果您真的想要深拷贝,请使用 Stack Overflow 上的搜索功能来查找现有的优秀答案。
据报道,切片现在明显更快
为什么是 Array.prototype.slice.call(arr).sort(); 而不是 arr.slice().sort();
J
JaredPar

尝试以下

function sortCopy(arr) { 
  return arr.slice(0).sort();
}

slice(0) 表达式创建从元素 0 开始的数组副本。


z
zzzzBov

您可以使用不带参数的 slice 来复制数组:

var foo,
    bar;
foo = [3,1,2];
bar = foo.slice().sort();

这个答案太棒了!我很惊讶 JavaScript 允许突变到这种程度。似乎错了。再次感谢。
A
Aditya Agarwal

你也可以这样做

d = [20, 30, 10]
e = Array.from(d)
e.sort()

这样 d 就不会发生突变。

function sorted(arr) {
  temp = Array.from(arr)
  return temp.sort()
}

//Use it like this
x = [20, 10, 100]
console.log(sorted(x))

这个答案很好
H
Hamada

任何想要进行深拷贝(例如,如果您的数组包含对象)的人都可以使用:

let arrCopy = JSON.parse(JSON.stringify(arr))

然后您可以在不更改 arr 的情况下对 arrCopy 进行排序。

arrCopy.sort((obj1, obj2) => obj1.id > obj2.id)

请注意:对于非常大的阵列,这可能会很慢。


这将在您的第二个示例中使用 - 而不是 >
并记住您的所有项目都应该是可序列化的,以便在字符串化后将它们带回来(例如,日期对象、函数和符号在此方法中存在问题)
R
Ran Turner

更新 - Array.prototype.toSorted() 个提案

Array.prototype.toSorted(compareFn) -> Array 是一种建议添加到 Array.prototype 的方法,目前在 stage 3 中(即将可用)。

此方法将保持目标 Array 不变,并返回它的副本并执行更改。


P
Prati

试试这个对数字进行排序。这不会改变原始数组。

function sort(arr) {
  return arr.slice(0).sort((a,b) => a-b);
}

J
Josh

有一个新的 tc39 proposal,它向 Array 添加了一个 toSorted 方法,该方法返回数组的副本并且不修改原始数组。

例如:

const sequence = [3, 2, 1];
sequence.toSorted(); // => [1, 2, 3]
sequence; // => [3, 2, 1]

由于它目前处于第 3 阶段,它可能很快会在浏览器引擎中实现,但与此同时,可以在 herecore-js 中使用 polyfill。


O
Oleh Dzoba

我认为我的回答有点晚了,但如果有人再次遇到这个问题,解决方案可能会有用。

我可以提出另一种使用返回排序数组的本机函数的方法。

此代码仍会改变原始对象,但此实现不会返回原生行为,而是返回排序数组。

// Remember that it is not recommended to extend build-in prototypes 
// or even worse override native functions.  
// You can create a seperate function if you like

// You can specify any name instead of "sorted" (Python-like)

// Check for existence of the method in prototype
if (typeof Array.prototype.sorted == "undefined") {
  // If it does not exist you provide your own method
  Array.prototype.sorted = function () {
    Array.prototype.sort.apply(this, arguments);
    return this;
  };
}

这种解决问题的方法在我的情况下是理想的。