I'm from an imperative programming background (Java) and starting to try understand FP concepts better. In particular conditional branching/filtering and how it can apply to streams/lists of data.
Here's a silly contrived example...we have a list of players and want to separate them into different lists based on their skill-levels. A basic imperative approach could be something like:
const excluded = []; // LOW skilled
const reserves = []; // only MEDIUM/HIGH skilled
const team = []; // only HIGH skilled
const allPlayers = [
{
name: 'personh1',
skillLevel: 'HIGH'
},
{
name: 'personh2',
skillLevel: 'HIGH'
},
{
name: 'personh3',
skillLevel: 'HIGH'
},
{
name: 'personm1',
skillLevel: 'MEDIUM'
},
{
name: 'personm2',
skillLevel: 'MEDIUM'
},
{
name: 'personl1',
skillLevel: 'LOW'
},
{
name: 'personl2',
skillLevel: 'LOW'
}
];
const maxTeamSize = 2;
const maxReservesSize = 2;
allPlayers.forEach(p => {
if (p.skillLevel === 'HIGH') {
if (team.length < maxTeamSize) {
team.push(p);
} else {
reserves.push(p);
}
} else if (p.skillLevel === 'MEDIUM') {
if (reserves.length < maxReservesSize) {
reserves.push(p);
} else {
excluded.push(p);
}
} else {
excluded.push(p);
}
});
// functions defined elsewhere...
notifyOfInclusion(team.concat(reserves));
notifyOfExclusion(excluded);
I can accomplish this in a more functional manner: (using JS and the Ramda library):
team = R.slice(0, maxTeamSize, R.filter(p => p.skillLevel === 'HIGH', allPlayers));
reserves = R.slice(0, maxReservesSize, R.filter(p => (p.skillLevel === 'HIGH' || p.skillLevel === 'MEDIUM') && !R.contains(p, team), allPlayers));
excluded = R.filter(p => !R.contains(p, team) && !R.contains(p, reserves), allPlayers);
notifyOfInclusion(team.concat(reserves));
notifyOfExclusion(excluded);
But it seems very crude, repetitive and not very declarative. What is a better (more elegant/declarative) way of achieving something like this from a functional POV? Using Ramda in any answers would be a bonus but not essential. Thanks.