Сортировка массива с функцией уменьшения 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)
  )
);