Сортировка массива с помощью функции 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
вместо других функций массива.