Як можна сортувати масив, не змінюючи початковий масив?


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

1
@evanmcdonnal Неглибока копія може бути досить хорошою, якщо все, що потрібно, - це переупорядкування, а не дублікат кожного елемента в масиві.
Кекоа

.sortпотрібно, щоб thisзначення було масивом, тому для останнього фрагмента ви працюєте .sort.call(arr)(хоча це не вирішує вашу проблему).
pimvdb

@Kekoa Так, це хороший момент. Не потрібно витрачати більше пам’яті, якщо ви збираєтесь лише змінити порядок елементів, а не самі елементи.
evanmcdonnal

Метод zzzzBov працює як шарм! stackoverflow.com/a/9592774/7011860
Самет М.

Відповіді:


222

Просто скопіюйте масив. Є багато способів зробити це:

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

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

2
Чи буде це робити глибоку копію, тобто чи будуть скопійовані вкладені об'єкти та масиви?
Пітер Ольсон

2
Чи є якась перевага в застосуванні concatover say slice(0)або вони всі майже однакові?
ДжаредПар

3
@PeterOlson Ні, це неглибока копія. Якщо ви дійсно хочете отримати глибоку копію, скористайтеся функцією пошуку на стеку Overflow, щоб знайти існуючі чудові відповіді на це.
Роб Ш

11
Зараз про зріз помітно швидше
Зандер Браун

3
чому Array.prototype.slice.call(arr).sort();замість arr.slice().sort();?
Олів’є Боассе


61

Спробуйте наступне

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

slice(0)Вираз створює копію масиву , починаючи з елемента 0.


32

Ви можете використовувати фрагмент без аргументів для копіювання масиву:

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

Однак, переглянувши коментарі ОП, я дослідив трохи глибоке копіювання і виявляється, що Object.assign не тільки виконує дрібну копію, але й лише вибирає численні та власні властивості (про що відповів у цій публікації ).

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.