Сортировка массива с помощью функции JavaScript reduce

часто я изучаю некоторые JavaScript интервью вопросы, вдруг я увидел вопрос об использовании reduce функция для сортировки Array, Я читал об этом в MDN и использование его в некоторых medium статьи, но сортировка в Array - это так инновационно:

const arr = [91,4,6,24,8,7,59,3,13,0,11,98,54,23,52,87,4];

я много думал, но я понятия не имею, как ответить на этот вопрос, как должно быть reduce

8 ответов


здесь нет смысла использовать reduce, однако вы можете использовать новый массив в качестве аккумулятора и выполнять сортировку вставки со всеми элементами:

array.reduce((sorted, el) => {
  let index = 0;
  while(index < array.length && el < array[index]) index++;
  sorted.splice(index, 0, el);
  return sorted;
}, []);

вот версия без сокращения:

array.sort((a, b) => a - b);

теперь несколько общих советов для написания редукторов:

как должна быть функция обратного вызова reduce?

вы или принимаете подход с аккумулятором, тогда редуктор должен приложить изменение к аккумулятор на основе текущего элемента и вернуть его:

(acc, el) => acc

или если аккумулятор и элементы имеют нормальный тип и логически равны, вам не нужно различать их:

 (a, b) => a + b

что такое initialValue функции уменьшения?

вы должны спросить себя " что должно уменьшить возврат, когда он применяется к пустому массиву?"

теперь самое главное: когда использовать уменьшить? (IMO)

если вы хотите свести значения массива к одно значение или объект.


Array.sort мутирует массив, где, используя Array.reduce поощряет чистую функцию. Вы можете клонировать массив перед сортировкой.

Я считаю, что этот вопрос призван заставить вас думать по-другому, применяя ограничения. Он проверяет ваши знания о том, как reduce работает, и, как показывают ответы, есть много способов снять кожу с кошки. Это покажет ваш личный вкус js в решении этого.

я решил использовать Array.findIndex и Array.splice.

const sortingReducer = (accumulator, value) => {
  const nextIndex = accumulator.findIndex(i => value < i );
  const index = nextIndex > -1 ? nextIndex : accumulator.length;
  accumulator.splice(index, 0, value);
  return accumulator;
}

const input = [5,4,9,1];
const output = input.reduce(sortingReducer, []);

тестирование с входной сигнал образца производит

arr.reduce(sortingReducer, [])
// (17) [0, 3, 4, 4, 6, 7, 8, 11, 13, 23, 24, 52, 54, 59, 87, 91, 98]

вот пример sorting массив в порядке убывания с помощью функции reduce.

каково начальное значение функции reduce

в этой функции ниже начальным значением является [], который передается как thisArg в функцию reduce.

 array.reduce(function(acc,curr,currIndex,array){
        //rest of the code here
        },[]//this is initial value also known as thisArg)

таким образом, в основном передается пустой массив, и элементы будут перемещены в этот массив

аккумулятор здесь пустой матрица.

const arr = [91, 4, 6, 24, 8, 7, 59, 3, 13, 0, 11, 98, 54, 23, 52, 87, 4];
var m = arr.reduce(function(acc, cur) {
  // this arrVar will have the initial array
  let arrVar = arr;
  // get the max element from the array using Math.max
  // ... is spread operator
  var getMaxElem = Math.max(...arrVar);
  // in the accumulator we are pushing the max value
  acc.push(getMaxElem);
  // now need to remove the max value from the array, so that next time it 
  // shouldn't not be considered
  // splice will return a new array
  // now the arrVar is a new array and it does not contain the current
  // max value
  arrVar = arrVar.splice(arrVar.indexOf(getMaxElem), 1, '')
  return acc;
}, []);
console.log(m)

reduce ограничения себя онлайн сортировка алгоритмы, где каждый элемент в массиве виден один раз, и теперь вы не заранее длина вашего массива (обратите внимание, что с помощью замыканий вы могли бы дать больше информации функции уменьшения, но этот вид поражает цель вопроса).

сортировка вставки-очевидный и простой пример; я не буду подробно описывать реализацию, поскольку другие ответы уже очень хороши в этом отношении. Однако вы можете упомяните несколько оптимизаций, которые, вероятно, могут рассматриваться как очень положительные для интервьюера:

  • использование двоичного поиска для поиска точки вставки может уменьшить сложность шага вставки от O(n) до O (log n). Это называется сортировкой двоичной вставки: общее количество сравнений будет идти от O(n^2) до O (N log n). Это не будет быстрее, потому что реальная стоимость связана с "сращиванием" выходного массива, но если у вас были дорогие сравнения (скажем, сортировка длинных строк для пример) это может иметь значение.

  • Если вы сортируете целое число, вы можете использовать radix sort и реализовать линейный алгоритм онлайн-сортировки с уменьшением. Это довольно сложно реализовать,но очень подходит для сокращения.


вот (imo) более элегантная версия Джонас Вт решение для сортировки вставки. Обратный вызов просто строит новый массив всех более низких значений, новый и все более высокие значения. Избегает использования явных циклов или индексов, поэтому легче сразу увидеть, что он работает правильно.

const insertValue = (arr, value) =>
  [...arr.filter(n => n <= value), value, ...arr.filter(n => n > value)]

const testArr = [91, 4, 6, 24, 8, 7, 59, 3, 13, 0, 11, 98, 54, 23, 52, 87, 4]

console.log(testArr.reduce(insertValue, []))

хотя reduce не идеально подходит для сортировки. Следующее решение похоже на forEach или любая функция цикла, которая пытается быть достигнута с помощью


вы можете использовать некоторые функции для получения массива, если не указан массив, функция, которая возвращает отсортированный массив, принимая два параметра и обратный вызов сортировки, который включает в себя выше, используя другой метод reduce для получения результата части отсортированного массива.

const
    getArray = a => Array.isArray(a) ? a : [a],
    order = (a, b) => a < b ? [a, b] : [b, a],
    sort = (a, b) => getArray(a).reduce((r, v) => r.concat(order(r.pop(), v)), [b]),
    array = [91, 4, 6, 24, 8, 7, 59, 3, 13, 0, 11, 98, 54, 23, 52, 87, 4];

console.log(array.reduce(sort));
.as-console-wrapper { max-height: 100% !important; top: 0; }

вы можете использовать сортировка вставками:

let array        = [91, 4, 6, 24, 8, 7, 59, 3, 13, 0, 11, 98, 54, 23, 52, 87, 4];
let countIfLess  = (array,v)=> array.reduce((c,n)=>n<v?c+1:c,0);
let countIfEqual = (array,v)=> array.reduce((c,n)=>n==v?c+1:c,0);

console.log(
  array.reduce(
    (a,v,i,array)=>( a[countIfLess(array,v) + countIfEqual(a,v)]=v, a ),
    new Array(array.length)
  )
);

Это создаст целевой массив один раз, а затем выполнит вставки в него на каждом шаге сокращения без необходимости воссоздания целевого массива.

есть более эффективные способы реализации countIfEqual но я решил реализовать все функции с помощью reduce вместо других функций массива.