Обратный массив в Javascript без изменения исходного массива

190

Array.prototype.reverse инвертирует содержимое массива на месте (с мутацией) ...

Существует ли такая же простая стратегия обращения массива без изменения содержимого исходного массива (без мутации)?

sfletche
источник
Вот эталонный тест, сравнивающий различные варианты: jsben.ch/HZ7Zp
Соломон Уцко

Ответы:

377

Вы можете использовать slice (), чтобы сделать копию, а затем перевернуть () ее

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

Арун П Джонни
источник
Можете ли вы объяснить slice () без параметров?
Алекс
3
@ Алекс ломтик - If begin is omitted, slice begins from index 0.- так же, какarray.slice(0)
Арун П Джонни
2
Я думаю, что @Alex имел в виду «объяснить это в своем ответе» ... независимо ... блестящее решение. Спасибо!
sfletche
14
Я НЕ рекомендовал бы использовать этот подход, потому что это очень вводящая в заблуждение практика. Это очень сбивает с толку, когда вы используете slice () и на самом деле вы ничего не нарезаете. Если вам нужен неизменный реверс, просто создайте новую новую копию: const newArray = [... array] .reverse ()
Олег Матей,
105

В 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медленный аф
Драгос Ризеску
@DragosRizescu Можете ли вы поделиться некоторыми примерами результатов испытаний?
Мухаммед Усман
1
Вот репозиторий, с которым вы можете поиграть: (не лучший пример, но этот аргумент был с кем-то некоторое время назад в контексте React, поэтому я собрал его вместе): github.com/rizedr/reduce-vs-reduceRight
Драгос Ризеску
4
(a, c) => a.concat([c])чувствует себя более идиоматичным, чем(a, c) => (a.push(c), a)
Кайл Лин
1
@DragosRizescu похоже, что это самый быстрый из трех лучших ответов. 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]), []);
hanswilw
источник
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

shekhardtu
источник
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]] 
}
daino3
источник
-4

ES6:

const reverseArr = [1,2,3,4].sort(()=>1)
Радион Пономаренко
источник
4
Добро пожаловать на Радион! Когда вы оставляете ответ, как правило, хорошая идея объяснить, почему ваш ответ работает и почему вы пришли к такому выводу, это помогает новым пользователям понять взаимодействия и языки, которые вы указали.
Итан Филд
В защиту Радион: P, что 1в конце могло бы быть больше нуля, потому что именно так работает Array.prototype.sortобратный вызов (или так называемый compare function). В основном вы всегда сравниваете 2 числа, и в этом случае сравнение возвращает всегда положительное значение, поэтому оно говорит, что всегда переходите ко второму числу перед первым :) это очень объяснительно: stackoverflow.com/questions/6567941/…
iulial
8
sort()мутирует массив (т.е. сортирует его на месте), чего хочет избежать OP.
Клинт Харрис
5
Этот ответ неверен в нескольких отношениях. (1) он мутирует массив, как указывает @ClintHarris, поэтому он не лучше, чем .reverse (). (2) ваш компаратор неправомерен - когда вы возвращаете 1 для a, b, вы должны вернуть отрицательное число для b, a. Если ваш ответ переворачивает массив в некоторых реализациях, это полностью удача.
Дон Хэтч