Страницы

Поиск по вопросам

суббота, 7 марта 2020 г.

Javascript Array.prototype.reduce

#javascript #массивы


Внимание: это не вопрос о том, как решить задачу симметричной разности. Это вопрос
про Array.prototype.reduce и как она работает.

Выполнял задания на freecodecamp, столкнулся с заданием по симметричной разности,
сделал через массивы, обычным способом, прошло проверки, всё хорошо. В полезных ссылках
были ссылки на ресурсы:

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce

https://www.youtube.com/watch?v=PxffSUQRkG4

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

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

Я понимаю, что она перебирает массив, и обрабатывает его, однако не могу понять как
функция, которая передаётся как callback-параметр в reduce, поняла какие массивы ей
сравнивать, как они ей так передались по очереди, попарно... Хочу разобраться с ней,
чтобы это не было каким-то неизвестным пропущенным местом в этом нелёгком изучении
javascript. Спасибо!

function sym() {
  var args = [];
    for (var i = 0; i < arguments.length; i++) {
        args.push(arguments[i]);
    }

    function symDiff(arrayOne, arrayTwo) {
        var result = [];

        arrayOne.forEach(function(item) {
            if (arrayTwo.indexOf(item) < 0 && result.indexOf(item) < 0) {
                result.push(item);
            }
        });

        arrayTwo.forEach(function(item) {
            if (arrayOne.indexOf(item) < 0 && result.indexOf(item) < 0) {
                result.push(item);
            }
        });

        return result;
    }

    return args.reduce(symDiff);
}

sym([1, 1, 2, 5], [2, 2, 3, 5], [3, 4, 5, 5]);

    


Ответы

Ответ 1



Эту операцию ещё называют "свёрткой". Она начинает с какого-то начального значения (если оно явно не указано, то обычно с первого элемента) и последовательно "заворачивает" в него элемент за элементом, пока коллекция (массив) не кончится. В вашем примере она обобщает симметрическую разность двух множеств (symDiff) на N множеств (sym). Проще всего объяснить механизм работы reduce для вашего случая будет так: sym(a, b, c) == [a, b, c].reduce(symDiff) == symDiff(symDiff(a, b), c) sym(a, b, c, d) == [a, b, c, d].reduce(symDiff) == symDiff(symDiff(symDiff(a, b), c), d) Забавно, что sym, в отличие от symDiff, может принимать и один аргумент. Его же в этом случае и вернёт. Если вы рассматриваете симметрическую разность одного элемента. Можно пойти ещё дальше и определить симметрическую разность нуля элементов. Нынешняя функция упадёт, попытавшись её вычислить. Распространённая практика для таких случаев это возвращать нейтральный элемент для переданной функции. Для симметрической разности это пустое множество. Достаточно просто передать его как начальное значение для reduce: return args.reduce(symDiff, []); ...и reduce начнёт "заворачивать" элементы не в первый элемент, а в него. А для пустой коллекции будет возвращён он же в неизменном виде. Минус, хоть и небольшой, в том, что для двух аргументов ваша версия вызовет symDiff единожды, а с упомянутым изменением — дважды.

Комментариев нет:

Отправить комментарий