Изи задачка по Javascript на метод reduce
Всем доброго дня! Дан вот такой многомерный массив: [['good', 'bAd', 'bad'], ['bad', 'bAd', 'bad', 'bad'], ['good', 'bAd', 'bad']]. Мне нужно вывести фразы, если в нем встречается 1 good, больше 2-ух good или если они отсутствуют. Вот мое решение:
let well = (x) => x.flat(Infinity).reduce(el => {
if (typeof(el) === 'string' && (el === 'good') === 1) {
return 'Publish!';
} else if (typeof(el) === 'string' && (el === ' good') > 2) {
return 'I smell a series!';
} else {
return 'Fail';
}
})
console.log(well([['good', 'bAd', 'bad'],
['bad', 'bAd', 'bad', 'bad'], ['good', 'bAd', 'bad']]));
Но оно не работает. Подскажите, что я делаю не так? Я хочу решить именно этим способом, так как учусь работать с методами map, filter и reduce.
Ответы (1 шт):
что я делаю не так?
Всё. Начиная с того, что reduce вовсе не подходит для данной задачи. Скорее filter()
let well = (x) => x.flat(Infinity).reduce(el => {
if (typeof(el) === 'string' && (el === 'good') === 1) {
return 'Publish!';
} else if (typeof(el) === 'string' && (el === ' good') > 2) {
return 'I smell a series!';
} else {
return 'Fail';
}
})
well([['good', 'bAd', 'bad'],
['bad', 'bAd', 'bad', 'bad'], ['good', 'bAd', 'bad']]);
x.flat(Infinity) Сразу из входного массива получаете плоский массив элементов good / bad.
.reduce(функция, начальное_значение)— начальное не указано, поэтому берется первый элемент указанного массива,'good'(el === 'good') === 1→ el === 'good' возвращает только true / false. Сравнивая значение типа boolean с числом 1, всегда будете получать false (из-за оператора строгого === сравнения. Типы не совпадают - до свидания)- Функция внутри reduce получает четыре параметра:
(текущее_значение_начальной_переменной, элемент, индекс, весь_массив)
То, что вернет эта функция - передается в качестве текущего значения (оно же, el) на следующую итерацию функции.
У вас после первой итерации el получит одно из значений Publish, I smell, Fail, и дальше будет бесполезно кругами бегать.
let status = get_publish_status([['good', 'bAd', 'bad'],
['bad', 'bAd', 'bad', 'bad'], ['good', 'bAd', 'bad']]);
console.log(status);
/***/
function get_publish_status(arr) {
let good = arr.flat(100).filter(str => /good/i.test(str)).length;
return ( good >= 2 ) ? ( 'I smell series!' ) : ( good == 1 ? 'Publish!' : 'Fail' );
}
P.s. Чтобы понять reduce, достаточно знать, что это одно и то же:
let arr = [1, 2, 3];
/***/
let sum = 0;
arr.forEach( (el, index) => {
sum += el;
});
console.log(sum);
/***/
let result = arr.reduce( (sum, el, index) => {
sum += el;
return sum;
}, 0);
console.log(result);
reduce просто таскает с собой лишнюю переменную, которую спокойно можно было объявить и вне перебора. Просто, компактная запись через reduce иногда удобна для мелких однострочных функций.
UPD: «Через reduce можно реализовать map и filter» (c) @Grundy
let status = get_publish_status([['good', 'bAd', 'bad'],
['bad', 'bAd', 'bad', 'bad'], ['good', 'bAd', 'bad']]);
console.log(status);
/***/
function get_publish_status(arr) {
let good = arr.flat(100).reduce(myFilter, []).length;
// Начальное значение (goods) - пустой [] массив
function myFilter(goods, word) {
if( /good/i.test( word ) ) goods.push(word);
return goods;
}
return ( good >= 2 ) ? ( 'I smell series!' ) : ( good == 1 ? 'Publish!' : 'Fail' );
}