Skip to content
This repository has been archived by the owner on Dec 15, 2021. It is now read-only.

Commit

Permalink
feat(countBy): Add module countBy
Browse files Browse the repository at this point in the history
  • Loading branch information
adambrgmn committed Jan 16, 2018
1 parent 2bcd328 commit c502e04
Show file tree
Hide file tree
Showing 3 changed files with 96 additions and 0 deletions.
78 changes: 78 additions & 0 deletions src/__tests__/countBy.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import countBy from '../countBy';

describe('Core.countBy', () => {
const albums = [
{ title: 'Art of the Fugue', artist: 'Glenn Gould', genre: 'Baroque' },
{ title: 'A Farewell to Kings', artist: 'Rush', genre: 'Rock' },
{ title: 'Timeout', artist: 'Dave Brubeck Quartet', genre: 'Jazz' },
{ title: 'Fly By Night', artist: 'Rush', genre: 'Rock' },
{
title: 'Goldberg Variations',
artist: 'Daniel Barenboim',
genre: 'Baroque',
},
{
title: 'New World Symphony',
artist: 'Leonard Bernstein',
genre: 'Romantic',
},
{ title: 'Romance with the Unseen', artist: 'Don Byron', genre: 'Jazz' },
{ title: 'Somewhere In Time', artist: 'Iron Maiden', genre: 'Metal' },
{ title: 'In Times of Desparation', artist: 'Danny Holt', genre: 'Modern' },
{ title: 'Evita', artist: 'Various', genre: 'Broadway' },
{ title: 'Five Leaves Left', artist: 'Nick Drake', genre: 'Folk' },
{
title: 'The Magic Flute',
artist: 'John Eliot Gardiner',
genre: 'Classical',
},
];

const prop = p => obj => obj[p];
const derivedGenre = album => {
const remap = {
Baroque: 'Classical',
Modern: 'Classical',
Romantic: 'Classical',
Metal: 'Rock' /* etc */,
};

const genre = prop('genre')(album);
return remap[genre] || genre;
};

test('counts by a simple property of the objects', () => {
expect(countBy(prop('genre'), albums)).toEqual({
Baroque: 2,
Rock: 2,
Jazz: 2,
Romantic: 1,
Metal: 1,
Modern: 1,
Broadway: 1,
Folk: 1,
Classical: 1,
});
});

test('counts by a more complex function on the objects', () => {
expect(countBy(derivedGenre, albums)).toEqual({
Classical: 5,
Rock: 3,
Jazz: 2,
Broadway: 1,
Folk: 1,
});
});

test('will force items into strings due to the nature of js objects', () => {
const list = [() => {}, 1, {}, []];
const id = x => x;
expect(countBy(id, list)).toEqual({
'() => {}': 1,
'1': 1,
'[object Object]': 1,
'': 1,
});
});
});
16 changes: 16 additions & 0 deletions src/countBy.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import reduce from './reduce';
import prop from './prop';
import assoc from './assoc';

const countBy = (fn, list) =>
reduce(
(acc, item) => {
const key = fn(item);
const existingKey = prop(key, acc);
return assoc(key, existingKey ? existingKey + 1 : 1, acc);
},
{},
list,
);

export { countBy as default };
2 changes: 2 additions & 0 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import assocPath from './assocPath';
import clamp from './clamp';
import compose from './compose';
import concat from './concat';
import countBy from './countBy';
import curry from './curry';
import dec from './dec';
import divide from './divide';
Expand Down Expand Up @@ -65,6 +66,7 @@ export {
clamp,
compose,
concat,
countBy,
curry,
dec,
divide,
Expand Down

0 comments on commit c502e04

Please sign in to comment.