Попытка найти четное и нечетное число с помощью уменьшения - PullRequest
0 голосов
/ 09 декабря 2018

Я пытаюсь решить проблему, описанную ниже, с помощью метода Reduce, но не могу получить правильное количество четных и нечетных чисел в объекте.

Может кто-нибудь подсказать мне, что не так в моем коде?

Создать функцию countBy, которая принимает массив и обратный вызов и возвращает объект.countBy будет перебирать массив и выполнять обратный вызов для каждого элемента.Каждое возвращаемое значение из обратного вызова будет сохранено как ключ на объекте.Значение, связанное с каждым ключом, будет количеством раз, которое конкретное возвращаемое значение было возвращено

function countBy(arr, fn) {
  return arr.reduce(function(acc, nums) {
    // console.log(nums);
    let oddCount = 0
    let evenCount = 0
    console.log(nums, fn(nums))
    if(fn(nums) === "even"){
      evenCount++;
      acc['even'] = evenCount;
    } else {
      oddCount++;
      acc['odd'] = oddCount;
    }
    return acc
  }, {}, 0)
}

function evenOdd(n) {
 if (n % 2 === 0) return "even";
 else return "odd";
}

var nums = [1, 2, 3, 4, 5];
console.log(countBy(nums, evenOdd)); // should log: { odd: 3, even: 2 }

Ответы [ 4 ]

0 голосов
/ 27 декабря 2018

Я бы начал с универсальной функции для увеличения ключа k на объекте o

const incr = k => ({ [k]: val = 0, ...o }) =>
  ({ ...o, [k]: val + 1 })
  
const incrFoo =
  incr ("foo")

console .log
  ( incrFoo ({})
    // { foo: 1 }
    
  , incrFoo ({ bar: 100 })
    // { bar: 100, foo: 1 }
    
  , incrFoo ({ foo: 3, bar: 100 })
    // { bar: 100, foo: 4 }
    
  , incr ("even") ({ odd: 2, even: 2 })
    // { odd: 2, even: 3 }
  )

Подключите его к reduce и countBy в основном пишет сам -

const incr = k => ({ [k]: val = 0, ...o }) =>
  ({ ...o, [k]: val + 1 })
  
const countBy = (f, xs = []) =>
  xs .reduce
    ( (acc, x) => incr (f (x)) (acc)
    , {}
    )

console .log
  ( countBy
      ( x => x & 1 ? "odd" : "even"
      , [ 1, 2, 3, 4, 5 ]
      )
      // { even: 2, odd: 3 }

  , countBy
      ( x => x
      , [ 'a', 'b', 'b', 'c', 'c', 'c' ]
      )
      // { a: 1, b: 2, c: 3 }
  )

Функции высшего порядка не ограничиваются map, filter и reduce - Используя комбинатор продолжения, $ ниже, мы показываем countBy как рекурсивная функция.В качестве дополнительного преимущества эта реализация принимает любые повторяемые в качестве входных данных;не только массивы.

const incr = k => ({ [k]: val = 0, ...o }) =>
  ({ ...o, [k]: val + 1 })
  
const $ = x => k =>
  k (x)
  
const None =
  Symbol ()
  
const countBy = (f, [ x = None, ...xs ]) =>
  x === None
    ? {}
    : $ (f (x))
        (key => $ (countBy (f, xs)) (incr (key)))
  
console .log
  ( countBy
      ( x => x & 1 ? "odd" : "even"
      , [ 1, 2, 3, 4, 5 ]
      )
      // { even: 2, odd: 3 }

  , countBy
      ( x => x
      , "mississippi"
      )
      // { p: 2, s: 4, i: 4, m: 1 }
  )
0 голосов
/ 09 декабря 2018

Как сказал CertainPerformance, вы переинициализируете переменные, которые используете для подсчета.Кроме того, вы отправляете дополнительный параметр для сокращения, которого не должно быть.Reduce принимает только 2 параметра.

Вот так я бы поступил

function countBy(arr, fn) {
  return arr.reduce(function(acc, nums) {
   console.log(nums, fn(nums))
    if(fn(nums) === "even"){
      acc.even ++;
    } else {
      acc.odd ++;
    }
    return acc
  }, {odd: 0, even: 0})
}

Это решается так, как вы хотите, согласно журналу.Если бы вы следовали командам, я думаю, что на самом деле это выглядело бы так:

function countBy(arr, fn) {
  return arr.reduce(function(acc, val) {
    let key = fn(nums);
    if (!acc[key]) {
      acc[key] = 1;
    } else {
      acc[key]++;
    }
    return acc;
  }, {})
}

Ваша первоначальная попытка основывается на функции обратного вызова, возвращающей «нечетный» или «четный» для работы.Этот код выше может работать с функцией, возвращающей любое значение

0 голосов
/ 09 декабря 2018

Кроме Array.reduce, вы также можете решить эту проблему немного иначе с помощью Array.forEach и вспомогательной функции:

const isEvenOrOdd = n => n % 2 ? "even" : "odd"
const propCount = (prop, obj) => obj[prop] = (obj[prop] || 0) + 1

const countBy = (arr, fn, obj={}) => {
  arr.forEach(x => propCount(isEvenOrOdd(x), obj))
  return obj
}

console.log(countBy([1, 2, 3, 4, 5], isEvenOrOdd));
0 голосов
/ 09 декабря 2018

Вы инициализируете oddCount и evenCount в 0 внутри обратного вызова reduce, поэтому на каждой итерации ваш

evenCount++;
acc['even'] = evenCount;

только когда-либоувеличение evenCount или oddCount до 1.Вместо этого инициализируйте счетчики вне обратного вызова, чтобы их изменения были постоянными при нескольких вызовах обратного вызова reduce:

function countBy(arr, fn) {
  let oddCount = 0
  let evenCount = 0
  return arr.reduce(function(acc, nums) {
    // console.log(nums);
    console.log(nums, fn(nums))
    if (fn(nums) === "even") {
      evenCount++;
      acc['even'] = evenCount;
    } else {
      oddCount++;
      acc['odd'] = oddCount;
    }
    return acc
  }, {}, 0)

}

function evenOdd(n) {
  if (n % 2 === 0) return "even";
  else return "odd";
}
var nums = [1, 2, 3, 4, 5];
console.log(countBy(nums, evenOdd)); // should log: { odd: 3, even: 2 }

Или вы можете полностью исключить внешние переменные, проверив значение свойства уже на аккумуляторе:

const countBy = (arr, fn) => arr.reduce((acc, num) => {
  const prop = fn(num);
  acc[prop] = (acc[prop] || 0) + 1;
  return acc;
}, {});

function evenOdd(n) {
  if (n % 2 === 0) return "even";
  else return "odd";
}
var nums = [1, 2, 3, 4, 5];
console.log(countBy(nums, evenOdd)); // should log: { odd: 3, even: 2 }
...