Javascript: использование reduce() для поиска минимального и максимального значений?

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

/**
 * Takes an array of numbers and returns an array of size 2,
 * where the first element is the smallest element in items,
 * and the second element is the largest element in items.
 *
 * Must do this by using a single call to reduce.
 *
 * For example, minMax([4, 1, 2, 7, 6]) returns [1, 7]
 */
function minMax(items) {
     var minMaxArray = items.reduce(
        (accumulator, currentValue) => {
             return (accumulator < currentValue ? accumulator : currentValue);
        }
    );

     return minMaxArray;
 }

person Alyssa June    schedule 23.04.2017    source источник
comment
Похоже, вы забыли задать вопрос. Ознакомьтесь с разделом Как задать вопрос.   -  person zzzzBov    schedule 23.04.2017
comment
but I know that the reduce() method always returns an array of size 1 - это неверно. Кроме того, сокращение — это просто метод для перебора массива с обратным вызовом, подумайте о том, какие другие переменные вы можете иметь в области видимости внутри вашего метода minMax, которые вы можете использовать в итераторе. Подсказка: судя по вашему описанию, вам вовсе не обязательно использовать возвращаемое значение reduce.   -  person Adam    schedule 23.04.2017
comment
Прочтите документацию reduce() и измените initValue из accumulator   -  person charlietfl    schedule 23.04.2017


Ответы (12)


Хитрость заключается в предоставлении пустого массива в качестве параметра initialValue.

arr.reduce(callback, [initialValue])

initialValue [Необязательно] Значение для использования в качестве первого аргумента при первом вызове обратного вызова. Если начальное значение не указано, будет использован первый элемент массива.

Таким образом, код будет выглядеть так:

function minMax(items) {
    return items.reduce((acc, val) => {
        acc[0] = ( acc[0] === undefined || val < acc[0] ) ? val : acc[0]
        acc[1] = ( acc[1] === undefined || val > acc[1] ) ? val : acc[1]
        return acc;
    }, []);
}
person colxi    schedule 23.04.2017
comment
Преимущество этого ответа заключается в том, что он работает с произвольными упорядоченными типами (например, строками), а не только с числовыми значениями, что является хорошим обобщением. Одной из возможных оптимизаций было бы сделать initialValue равным [items[0], items[0]], чтобы вы могли избежать специального регистра undefined, упрощая вычисления минимума/максимума при каждом вызове if (val < acc[0]) acc[0] = val; и if (val > acc[1]) acc[1] = val;. - person ShadowRanger; 06.01.2018

В ES6 вы можете использовать оператор распространения. Одно строковое решение:

 Math.min(...items)
person Sergey Zhukov    schedule 22.11.2017
comment
Запрашивает Мин и Макс. - person colxi; 27.04.2018
comment
Хороший. Я не знал, что вы можете использовать Math.min так. Я делал только Math.min(a,b). - person Lonelydatum; 13.09.2018
comment
Это падает с большими массивами - person Jimmy Kane; 21.09.2018
comment
Чтобы уточнить ответ @JimmyKane, если вы используете большие массивы, то есть предоставляете Math.min() много аргументов: › вы рискуете превысить ограничение длины аргумента движка JavaScript. Последствия применения функции со слишком большим количеством аргументов (думаю, более десятков тысяч аргументов) различаются в зависимости от движка (JavaScriptCore имеет жестко запрограммированное ограничение аргументов 65536), ... developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/ - person tobias; 02.04.2019

Вы можете использовать массив в качестве возвращаемого значения:

function minMax(items) {
    return items.reduce(
        (accumulator, currentValue) => {
            return [
                Math.min(currentValue, accumulator[0]), 
                Math.max(currentValue, accumulator[1])
            ];
        }, [Number.MAX_VALUE, Number.MIN_VALUE]
    );
}
person Ilyas Kabirov    schedule 23.04.2017
comment
+1, однако MIN_VALUE сбивает с толку наименьшее положительное значение (›0). Вам лучше использовать Number.INFINITY и Number.NEGATIVE_INFINITY - person Bergi; 24.04.2017
comment
@Bergi Берги Я думаю, ты имеешь в виду Number.POSITIVE_INFINITY... нет Number.INFINITY. - person mgthomas99; 21.11.2018

Решение с использованием функций Math.min() и Math.max():

function minMax(items) {
    var minMaxArray = items.reduce(function (r, n) {
            r[0] = (!r[0])? n : Math.min(r[0], n);
            r[1] = (!r[1])? n : Math.max(r[1], n);
            return r;
        }, []);

    return minMaxArray;
}

console.log(minMax([4, 1, 2, 7, 6]));

person RomanPerekhrest    schedule 23.04.2017

Поскольку вызов сокращения на самом деле не нужен, вы можете повеселиться с ним.

let items = [62, 3, 7, 9, 33, 6, 322, 67, 853];

let arr = items.reduce((w,o,r,k,s=Math)=>[s.min.apply(0, k),s.max.apply(0, k)],[]);

console.log(arr);

Все, что вам действительно нужно, это let minMaxArray = [Math.min.apply(0,items), Math.max.apply(0,items)]

person adeneo    schedule 23.04.2017

Вы можете использовать сделать так. Аргументов может быть сколько угодно.

function minValue(...args) {
    const min = args.reduce((acc, val) => {
        return acc < val ? acc : val;
    });
    return min;
}

function maxValue(...args) {
    const max= args.reduce((acc, val) => {
        return acc > val ? acc : val;
    });
    return max;
}
person Abishek Bardewa    schedule 01.12.2020
comment
Это правильное решение. Я не понял, почему все используют функции Math, когда они явно не нужны. - person attacomsian; 10.04.2021

Чтобы получить минимальное и максимальное значение массива, используя функцию уменьшения

const ArrayList = [1, 2, 3, 4, 3, 20, 0];
const LargestNum = ArrayList.reduce((prev, curr) => {
      return Math.max(prev, curr)
});
const MinNum = ArrayList.reduce((prev,curr)=>{
      return Math.min(prev,curr)
});
console.log(LargestNum);
console.log(MinNum);
person Ahmed Mahmoud    schedule 13.04.2019
comment
В вашем примере это работает только потому, что последними значениями массива являются 20 и 0, и они сравниваются последними. Просто попробуйте поместить минимальное и максимальное значения в начало вашего массива, и мы увидим, работает ли ваш код :) - person Alex; 29.10.2020
comment
После ввода 0,20 в начале массива все еще работает без проблем, выход равен 20,0 - person Ahmed Mahmoud; 30.10.2020
comment
Хорошо, я слишком быстро прочитал ваш ответ, прочитав еще раз, кажется, что он правильный. Мои извинения - person Alex; 03.11.2020

let arr = [8978, 'lol', -78, 989, NaN, null, undefined, 6, 9, 55, 989];


let minMax = arr.reduce(([min, max], v) => [
                Math.min(min, v) || min,
                Math.max(max, v) || max], [Infinity, -Infinity]);


console.log(minMax);

Как это работает:

  1. || min чек v номер.

  2. [Infinity, -Infinity] это .reduce начальное значение

  3. Он использует присваивание js destructuring

person SlimeSli    schedule 05.02.2020
comment
Добро пожаловать в Stack Overflow! Пожалуйста, объясните свой ответ. Не просто пишите код. Для справки см. Как ответить - person tobsob; 05.02.2020

1. Решение с использованием только Math.min и Math.max:

⚠️ Это не сработает, если вы используете большие массивы, т. е. предоставляете Math.min() много аргументов, так как вы рискуете превысить ограничение длины аргумента движка JavaScript. Последствия применения функции со слишком большим количеством аргументов (думаю, более десятков тысяч аргументов) различаются в зависимости от движка (JavaScriptCore имеет жестко запрограммированное ограничение на количество аргументов, равное 65 536), потому что ограничение (на самом деле, даже природа любого чрезмерно большого стека поведение) не указано. Некоторые механизмы выдают исключение. из веб-документов MDN.

function minMax(items) {
  return [
      Math.min.apply(null, items),
      Math.max.apply(null, items)
  ]
}

... или если вы предпочитаете синтаксис Spread ES6:

const minMax = items => [
  Math.min(...items),
  Math.max(...items)
]

2. Решение с использованием Array.prototype.reduce, Math.min и Math.max

function minMax(arr) {
  return arr.reduce(function(acc, cur) {
    return [
      Math.min(cur, acc[0]),
      Math.max(cur, acc[1])
    ]
  }, [Number.POSITIVE_INFINITY, Number.NEGATIVE_INFINITY]);
}

... или сокращенно:

const minMax = items =>
  items.reduce((acc, cur) =>
    [Math.min(cur, acc[0]), Math.max(cur, acc[1])],
    [Number.POSITIVE_INFINITY, Number.NEGATIVE_INFINITY]
  )

3. Решение, включающее разумные проверки

function minMax(items) {
  let newItems = []
  const isArray = Array.isArray(items)
  const onlyHasNumbers = !items.some(i => isNaN(parseFloat(i)))

  // only proceed if items is a non-empty array of numbers
  if (isArray && items.length > 0 && onlyHasNumbers) {
    newItems = items.reduce((acc, cur) => [
        Math.min(cur, acc[0]),
        Math.max(cur, acc[1])
      ], [Number.POSITIVE_INFINITY, Number.NEGATIVE_INFINITY])
  }

  return newItems
}

Документация для Math.min

Документация по Math. макс

Документация для Array.prototype.reduce()< /а>

person tobias    schedule 06.04.2019

Мы можем добиться этого, объявив пустой массив в качестве значения аккумулятора для функции сокращения, а затем выполнив другой набор операций на последней итерации метода сокращения. Мы делаем это, передавая все четыре параметра методу сокращения (total, item, index, array) и используя сравнение индекса с длиной массива, чтобы сделать что-то другое на этой последней итерации.

var prices = [32.99, 21.99, 6.99, 4.99, 12.99, 8.98, 5.99];

var highLowPrices = prices.reduce(function(accumulatorArray, price, index, pricesArray){
    if (index === pricesArray.length-1){
        accumulatorArray.push(price);
        var returnArray = [];
        accumulatorArray.sort(function(price1, price2){
            return price1 - price2;
        });
        var lowestPrice = accumulatorArray[0];
        var highestPrice = accumulatorArray[accumulatorArray.length-1];
        returnArray.push(lowestPrice);
        returnArray.push(highestPrice);
        return returnArray;
    } else {
        accumulatorArray.push(price);
        return accumulatorArray;
    }
}, []);

console.log(highLowPrices);

Я намеренно использовал несколько шагов больше, чем необходимо, и использовал семантически подробные имена переменных, чтобы сделать логику более понятной.

if (index === pricesArray.length-1) означает, что на последней итерации метода сокращения массива цен выполняется другой набор операций. До этого момента мы просто воссоздаем массив цен, что тривиально. Но на последней итерации, после полного воссоздания массива цен, мы делаем что-то другое. Мы создаем еще один пустой массив, тот, который мы собираемся вернуть. Затем мы сортируем переменную 'accumulatorArray', которая является воссозданным массивом цен, сортируя его от самой низкой до самой высокой. Теперь мы берем самую низкую цену и самую высокую цену и сохраняем их в переменных. Отсортировав массив в порядке возрастания, мы знаем, что самый низкий индекс находится в индексе 0, а самый высокий — в индексе array.length - 1. Затем мы помещаем эти переменные в наш ранее объявленный возвращаемый массив. И вместо того, чтобы возвращать саму переменную-аккумулятор, мы возвращаем свой собственный специально объявленный возвращаемый массив. Результатом является массив с самой низкой ценой, а затем с самой высокой ценой.

person codeSeeker    schedule 08.05.2021

Я знаю, что на этот вопрос был дан ответ, но я отказался от ответа @Sergey Zhukov (который кажется неполным) и смог получить минимальное и максимальное значения в двух строках:

let vals = [ numeric values ]
let min = Math.min.apply(undefined, vals) 
let max = Math.max.apply(undefined, vals)

Я вижу значение в Array.reduce, но с таким очень простым вариантом использования и, если вы понимаете, что делает Function.apply, это будет моим решением для перехода.

person jusopi    schedule 18.10.2018

person    schedule
comment
Пожалуйста, добавьте некоторые пояснения к вашему коду, чтобы другие могли учиться на нем. - person Nico Haase; 24.01.2020