peter flanagan
peter flanagan

Reputation: 9790

Ramda - combine duplicates of objects in array with same key value

I have an array of objects, where I want to combine if they have the same name, and add their feederTeams into an array.

The array looks like this:

const TEAMS = [{
    name: 'Liverpool',
    id: '1',
    feederTeam: 'Tranmere'
}, {
    name: 'Liverpool',
    id: '2',
    feederTeam: 'Stockport'
}, {
    name: 'Man Utd',
    feederTeam: 'Bla',
    id: '3',
}, {
    name: 'Liverpool',
    id: '6',
    feederTeam: 'Oldham'
}]

and I want to transform it into this using Ramda:

[{
    name: 'Liverpool',
    feederTeam: ['Tranmere', 'Stockport', 'Oldham']
}, {
    name: 'Man Utd',
    feederTeam: ['Bla'],
}]

I have tried many approaches with no luck. Here is my latest attempt.

R.forEach((team => R.filter(R.propEq('name', team.name), TEAMS)), TEAMS); 

Upvotes: 2

Views: 1119

Answers (1)

Ori Drori
Ori Drori

Reputation: 191976

Since you want to group several elements together use R.groupBy. Then get an array from the object of groups with R.values, and map each group to the required form:

const { pipe, groupBy, prop, values, map, applySpec, nth } = R

const fn = pipe(
  groupBy(prop('name')), // group object by the name property
  values, // get an array of groups
  map(applySpec({ // map each group to an object
    name: pipe(nth(0), prop('name')), // take the name from the 1st object in the group
    feederTeam: map(prop('feederTeam')), // collect all feedTeam props to an array
  })),
)

const teams = [{"name":"Liverpool","id":"1","feederTeam":"Tranmere"},{"name":"Liverpool","id":"2","feederTeam":"Stockport"},{"name":"Man Utd","feederTeam":"Bla","id":"3"},{"name":"Liverpool","id":"6","feederTeam":"Oldham"}]

const result = fn(teams)

console.log(result)
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.27.1/ramda.js" integrity="sha512-3sdB9mAxNh2MIo6YkY05uY1qjkywAlDfCf5u1cSotv6k9CZUSyHVf4BJSpTYgla+YHLaHG8LUpqV7MHctlYzlw==" crossorigin="anonymous"></script>

A slight variation would be to map the object of groups with R.mapObjIndexed. In this case the name the key (is the 2nd param supplied to R.applySpec). After mapping the groups to objects, convert the result to an array with R.values:

const { pipe, groupBy, prop, values, mapObjIndexed, applySpec, map, nthArg } = R

const fn = pipe(
  groupBy(prop('name')), // group object by the name property
  mapObjIndexed(applySpec({ // map each group to an object
    name: nthArg(1), // take the name from key (2nd arg)
    feederTeam: map(prop('feederTeam')), // collect all feedTeam props to an array
  })),
  values, // convert to an array of objects
)

const teams = [{"name":"Liverpool","id":"1","feederTeam":"Tranmere"},{"name":"Liverpool","id":"2","feederTeam":"Stockport"},{"name":"Man Utd","feederTeam":"Bla","id":"3"},{"name":"Liverpool","id":"6","feederTeam":"Oldham"}]

const result = fn(teams)

console.log(result)
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.27.1/ramda.js" integrity="sha512-3sdB9mAxNh2MIo6YkY05uY1qjkywAlDfCf5u1cSotv6k9CZUSyHVf4BJSpTYgla+YHLaHG8LUpqV7MHctlYzlw==" crossorigin="anonymous"></script>

Upvotes: 3

Related Questions