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

Posted

技术标签:

【中文标题】如何在不改变原始数组的情况下对数组进行排序?【英文标题】:How can you sort an array without mutating the original array? 【发布时间】:2012-03-24 11:09:42 【问题描述】:

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

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 值作为数组,因此要使最后一个 sn-p 工作,您将执行 .sort.call(arr) (尽管它不能解决您的问题)。跨度> @Kekoa 是的,这是一个很好的观点。如果您只更改元素的顺序而不更改元素本身,则无需消耗更多内存。 zzzzBov 的方法非常有效! ***.com/a/9592774/7011860 【参考方案1】:

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

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 上的搜索功能来找到现有的优秀答案。 Slice 现在报告速度明显更快 为什么是Array.prototype.slice.call(arr).sort(); 而不是arr.slice().sort();【参考方案2】:

试试下面的

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

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

【讨论】:

【参考方案3】:

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

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

【讨论】:

这个答案太棒了!我很惊讶 javascript 允许突变到这种程度。似乎错了。再次感谢。【参考方案4】:

您需要先复制数组,然后再对其进行排序。使用 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 版本。【参考方案5】:

你也可以这样做

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

【讨论】:

这个答案很好【参考方案6】:

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

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

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

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

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

【讨论】:

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

以上是关于如何在不改变原始数组的情况下对数组进行排序?的主要内容,如果未能解决你的问题,请参考以下文章

在不循环 c++ 的情况下对 2D 数组进行分区

在不更改原始 RowState 的情况下对数据集中的数据表进行排序

如何在不更改原始数组的情况下更改函数中的数组? [复制]

如何在不考虑最后一个空白行的情况下对 jqGrid 进行排序

如何在不使用 Spark SQL 的情况下对 Spark 中的数据帧进行排序?

如何在不消除坐标的情况下对浮点坐标进行排序? [关闭]