Я бы начал с универсальной функции для увеличения ключа 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 }
)