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


230

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

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);
}

但它根本不起作用。

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


1
创建数组的深层副本并对其进行排序。
evanmcdonnal 2012年

1
@evanmcdonnal如果只需要重新排序而不是数组中每个项目的重复,则浅表副本可能就足够了。
Kekoa 2012年

.sort要求this值是数组,因此对于最后一个代码片段,您可以做.sort.call(arr)(尽管它不能解决您的问题)。
pimvdb'3

@Kekoa是的,这很不错。如果仅要更改元素的顺序而不是元素本身,则不需要消耗更多的内存。
evanmcdonnal 2012年

zzzzBov的方法就像是魅力一样!stackoverflow.com/a/9592774/7011860
Samet M.19年

Answers:


222

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

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

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

2
这会进行深层复制吗,即是否也会复制嵌套的对象和数组?
彼得·奥尔森

2
使用concat过度发言是否有任何优势,slice(0)或者它们几乎都是一样的?
JaredPar'3

3
@PeterOlson不,这是一个浅表。如果您确实想要深层副本,请使用Stack Overflow上的搜索功能来找到现有的出色答案。
罗布W

11
现在据报道,切片速度显着提高
Zander Brown

3
为什么要Array.prototype.slice.call(arr).sort();代替arr.slice().sort();
奥利维尔·布瓦西(OlivierBoissé)


61

尝试以下

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

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


32

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

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

这个答案真棒!我很惊讶JavaScript允许这种程度的变异。似乎不对。再次感谢。

12

您也可以这样做

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))

这个答案很好
Leasye

1

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

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

然后,您可以进行排序arrCopy而无需更改arr

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

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


这将工作-,而不是>在你的第二个例子。
pootzko

0

我对大多数副本使用Object.assign()

var copyArray = Object.assign([], originalArray).sort();

然而,通过OP评论看后,我研究了一下深度复制和转出Object.assign不仅执行浅拷贝,而且只选择枚举和自己的属性(如在回答这个职位)。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.