簡體   English   中英

如何在不改變原始數組的情況下對數組進行排序?

[英]How can you sort an array without mutating the original array?

假設我想要一個排序函數,它返回輸入數組的排序副本。 我天真地嘗試了這個

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

但它根本不起作用。

有沒有一種直接的解決方法,最好是一種不需要手動滾動我自己的排序算法或將數組的每個元素復制到一個新元素中的方法?

您需要先復制數組,然后再對其進行排序。 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

只需復制數組。 有很多方法可以做到這一點:

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

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

嘗試以下

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

slice(0)表達式從元素 0 開始創建數組的副本。

您可以使用不帶參數的 slice 來復制數組:

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

你也可以這樣做

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

任何想要進行深拷貝(例如,如果您的數組包含對象)的人都可以使用:

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

然后您可以在不更改arr的情況下對arrCopy進行排序。

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

請注意:對於非常大的陣列,這可能會很慢。

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

Array.prototype.toSorted(compareFn) -> Array是一種建議添加到Array.prototype的方法,目前處於第 3 階段(即將推出)。

此方法將保持目標 Array 不變,並返回它的副本並執行更改。

我對大多數副本使用Object.assign()

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

然而,通過OP評論看后,我研究了一下深拷貝和原來Object.assign不僅執行淺拷貝,而且只選擇枚舉和自己的屬性(如在回答這個職位 )。

試試這個對數字進行排序。 這不會改變原始數組。

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

有一個新的tc39 提案,它向Array添加了一個toSorted方法,該方法返回數組的副本並且不修改原始數組。

例如:

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

由於它目前處於第 3 階段,它可能很快就會在瀏覽器引擎中實現,但與此同時,這里core-js中提供了一個 polyfill。

我認為我的回答有點晚了,但如果有人再次遇到這個問題,解決方案可能會有用。

我可以提出另一種方法,使用返回排序數組的本機函數。

此代碼仍會改變原始對象,但此實現不會返回原生行為,而是返回排序數組。

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

這種解決問題的方法在我的情況下是理想的。

您還可以擴展現有的 Array 功能。 這允許將不同的數組函數鏈接在一起。

Array.prototype.sorted = function (compareFn) {
    const shallowCopy = this.slice();
    shallowCopy.sort(compareFn);

    return shallowCopy;
}

[1, 2, 3, 4, 5, 6]
    .filter(x => x % 2 == 0)
    .sorted((l, r) => r - l)
    .map(x => x * 2)

// -> [12, 8, 4]

打字稿相同:

// extensions.ts
Array.prototype.sorted = function (compareFn?: ((a: any, b: any) => number) | undefined) {
    const shallowCopy = this.slice();
    shallowCopy.sort(compareFn);

    return shallowCopy;
}

declare global {
    interface Array<T> {
        sorted(compareFn?: (a: T, b: T) => number): Array<T>;
    }
}

export {}

// index.ts
import 'extensions.ts';


[1, 2, 3, 4, 5, 6]
    .filter(x => x % 2 == 0)
    .sorted((l, r) => r - l)
    .map(x => x * 2)

// -> [12, 8, 4]

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM