Сортировка массива с функцией уменьшения JavaScript
Часто я изучаю некоторые вопросы интервью с 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];
Я много думал, но я понятия не имею, как ответить на этот вопрос, как должна быть функция call back
reduce
? что является initialValue
функции reduce
? и что такое accumulator
и currentValue
функции call back
reduce
?
И в конце, имеет ли этот способ некоторые преимущества, чем другие алгоритмы сортировки? Или полезно ли улучшить другие алгоритмы?
Ответы
Ответ 1
Здесь нет смысла использовать сокращение, однако вы можете использовать новый массив в качестве аккумулятора и делать сортировку со всеми элементами:
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);
Теперь некоторые общие советы для написания редукторов:
как должна быть функция обратного вызова уменьшения?
Вы либо используете подход с аккумулятором, то редуктор должен применять модификацию к аккумулятору на основе текущего элемента и возвращать его:
(acc, el) => acc
Или, если аккумулятор и элементы имеют разумный тип и логически равны, вам не нужно их различать:
(a, b) => a + b
что является начальным значением функции сокращения?
Вы должны спросить себя: "Что должно уменьшить возврат, когда оно применяется на пустом массиве?"
Теперь самое главное: когда использовать сокращение? (ИМО)
Если вы хотите свести значения массива в одно значение или объект.
Ответ 2
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]
Ответ 3
Ниже приведен пример sorting
массива в порядке убывания с использованием функции уменьшения.
что является начальным значением функции уменьшения
В этой нижеприведенной функции начальным значением является значение []
которое передается как thisArg
в функции уменьшения.
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)
Ответ 4
Здесь (imo) более элегантная версия решения сортировки Jonas W. Обратный вызов только строит новый массив всех более низких значений, новый и все более высокие значения. Избегает использования явных циклов или индексов, поэтому проще сразу увидеть, что он работает правильно.
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, []))
Ответ 5
reduce
ограничения самостоятельно к алгоритмам онлайн-сортировки, где каждый элемент в массиве рассматривается один раз, и вы не заранее заходите в длину вашего массива (обратите внимание, что с помощью закрытий вы могли бы предоставить больше информации для функции уменьшения, но эти виды поражений цели вопроса).
вставка сортировки является очевидным и легким примером; Я не буду подробно останавливаться на этом, так как другие ответы уже очень хороши в этом отношении. Однако вы можете упомянуть несколько оптимизаций, которые, вероятно, могут показаться очень позитивными для интервьюера:
-
Использование двоичного поиска для поиска точки вставки может уменьшить сложность этапа вставки от O (n) до O (log n). Это называется сортировкой двоичной вставки: общее число сравнений будет идти от O (n ^ 2) до O (n log n). Это не будет быстрее, потому что реальная стоимость связана с "сращиванием" выходного массива, но если у вас были дорогостоящие сравнения (например, сортировка длинных строк, например), это могло бы иметь значение.
-
Если вы сортируете целое число, вы можете использовать сортировку radix и реализовать линейный алгоритм онлайн-сортировки с уменьшением. Это довольно сложно реализовать, но очень подходит для сокращения.
Ответ 6
Хотя, сокращение не идеально подходит для сортировки. Следующее решение похоже на forEach
или любую функцию цикла, которая пытается быть достигнута с Array.reduce
функции Array.reduce
.
var arr = [91,4,6,24,8,7,59,3,13,0,11,98,54,23,52,87,4];
arr = arr.reduce(function(acc,val){
if(acc.length) {
var temp = [];
while(acc[acc.length -1] > val) {
temp.push(acc.pop());
}
acc.push(val);
while(temp.length) {
acc.push(temp.pop());
}
} else {
acc.push(val);
}
return acc;
}, []);
console.log(arr);
Ответ 7
Вы можете использовать некоторые функции для получения массива, если не массив, - функция, которая возвращает отсортированный массив, беря два параметра и обратный вызов сортировки, который включает в себя выше, используя другой метод уменьшения для получения результата части отсортированного массива.
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; }
Ответ 8
Вы можете использовать сортировку вставки:
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)
)
);