Зворотний масив у Javascript без мутації оригінального масиву


188

Array.prototype.reverse повертає вміст масиву на місце (з мутацією) ...

Чи існує аналогічно проста стратегія повернення масиву без зміни вмісту вихідного масиву (без мутації)?



Ось орієнтир, який порівнює різні варіанти: jsben.ch/HZ7Zp
Solomon Ucko

Відповіді:


375

Ви можете скористатися фрагментом (), щоб зробити копію, а потім повернути її назад ()

var newarray = array.slice().reverse();


Можете пояснити, будь-ласка, фрагмент () без параметрів?
Алекс

3
@Alex скибочка - If begin is omitted, slice begins from index 0.- так це те саме, щоarray.slice(0)
Арун П Джонні

2
Я думаю, що @Alex мав на увазі "поясніть це у своїй відповіді" ... незалежно ... Блискуче рішення. Дякую!
sfletche

12
Я НЕ рекомендую використовувати такий підхід, оскільки це дуже оманлива практика. Це дуже заплутано, коли ви використовуєте slice (), і ви насправді нічого не нарізаєте. Якщо вам потрібен незмінний зворотний бік, просто створіть нову нову копію: const newArray = [... array] .reverse ()
Олег Матей

104

У ES6:

const newArray = [...array].reverse()

2
Як порівняння результатів цього порівняння з результатом прийнятої відповіді? Вони однакові?
Кеті

@Katie Дуже схожий, і дуже швидко, і Chrome, здається, дає [...].reverseперевагу в дуже простому тестовому випадку. jsperf.com/reverse-vs-slice-reverse/1
Брайан М. Хант

4
Я послідовно отримую .sliceякнайшвидше.
Джеймс Койл

3
@JamesCoyle Це, ймовірно, залежить від браузера та ОС, але slice, швидше за все, швидше b / c [...]- це загальний ітерабельний масив, тому не можна робити так багато припущень. Крім того, цілком ймовірно, що sliceкраще оптимізовано виробництво / с, це було вже давно.
Брайан М. Хант

Мої думки точно.
Джеймс Койл

11

Ще один варіант ES6:

Ми також можемо використовувати .reduceRight()для створення зворотного масиву, фактично не повертаючи його.

let A = ['a', 'b', 'c', 'd', 'e', 'f'];

let B = A.reduceRight((a, c) => (a.push(c), a), []);

console.log(B);

Корисні ресурси:


2
reduceRightповільно аф
Драгош Різеску

@DragosRisescu Чи можете ви поділитися деякими зразками тестових зразків?
Мохаммед Усман

1
Ось репо, з яким можна грати: (не найкращий приклад, але цей аргумент був з кимось деякий час тому в контексті React, тому я все це склав): github.com/rizedr/reduce-vs-reduceRight
Драгош Різеску

4
(a, c) => a.concat([c])відчуває себе більш ідіоматичним, ніж(a, c) => (a.push(c), a)
Кайл Лін

1
@DragosRizescu насправді виглядає так, що це найшвидший з 3 найкращих відповідей. jsperf.com/reverse-vs-slice-reverse/3
DBosley

7

Спробуйте це рекурсивне рішення:

const reverse = ([head, ...tail]) => 
    tail.length === 0
        ? [head]                       // Base case -- cannot reverse a single element.
        : [...reverse(tail), head]     // Recursive case

reverse([1]);               // [1]
reverse([1,2,3]);           // [3,2,1]
reverse('hello').join('');  // 'olleh' -- Strings too!                              

1
Це виглядає так, що воно би зламало порожні масиви.
Маттіас

6

Альтернатива ES6 із використанням .reduce()та поширенням.

const foo = [1, 2, 3, 4];
const bar = foo.reduce((acc, b) => ([b, ...acc]), []);

В основному, це робиться - створити новий масив із наступним елементом у foo та розповсюдити накопичений масив для кожної ітерації після b.

[]
[1] => [1]
[2, ...[1]] => [2, 1]
[3, ...[2, 1]] => [3, 2, 1]
[4, ...[3, 2, 1]] => [4, 3, 2, 1]

Альтернативно, .reduceRight()як зазначено вище, але без .push()мутації.

const baz = foo.reduceRight((acc, b) => ([...acc, b]), []);

4

Існує кілька способів повернути масив без зміни. Двоє з них є

var array = [1,2,3,4,5,6,7,8,9,10];

// Using Splice
var reverseArray1 = array.splice().reverse(); // Fastest

// Using spread operator
var reverseArray2 = [...array].reverse();

// Using for loop 
var reverseArray3 = []; 
for(var i = array.length-1; i>=0; i--) {
  reverseArray.push(array[i]);
}

Тест на продуктивність http://jsben.ch/guftu


0

В звичайний Javascript:

function reverseArray(arr, num) {
  var newArray = [];
  for (let i = num; i <= arr.length - 1; i++) {
    newArray.push(arr[i]);
  }

  return newArray;
}

0

Реверсування на місці зі змінною свопом для демонстраційних цілей (але вам потрібна копія, якщо ви не хочете мутувати)

const myArr = ["a", "b", "c", "d"];
const copy = [...myArr];
for (let i = 0; i < (copy.length - 1) / 2; i++) {  
    const lastIndex = copy.length - 1 - i; 
    [copy[i], copy[lastIndex]] = [copy[lastIndex], copy[i]] 
}

-4

es6:

const reverseArr = [1,2,3,4].sort(()=>1)

4
Ласкаво просимо до SO, Radion! Залишаючи відповідь, зазвичай корисно пояснити, чому працює ваша відповідь і чому ви прийшли до цього висновку, це допомагає новим користувачам зрозуміти взаємодію та мови, які ви вказали.
Етан Філд

На захист Радіона: P, що 1в кінці могло бути щось більше нуля, тому що так працює Array.prototype.sortзворотний виклик (або так званий compare function). В принципі ви завжди порівняти 2 числа , і в цьому випадку повертається порівняння завжди позитивні , так він каже завжди перейти до другого номеру перед першою :) це дуже розумний: stackoverflow.com/questions/6567941 / ...
iulial

8
sort()мутує масив (тобто сортує його на місці), чого ОП хоче уникнути.
Клінт Харріс

5
Ця відповідь є помилковою з кількох способів. (1) він мутує масив, як вказує @ClintHarris, тому це не краще, ніж .reverse (). (2) ваш компаратор незаконний - коли ви повертаєте 1 для a, b, ви повинні повернути від’ємне число для b, a. Якщо ваша відповідь обертає масив для деяких реалізацій, це зовсім на удачу.
Дон Хетч
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.