Home > front end >  Nesting by levels from flatten array of objects
Nesting by levels from flatten array of objects

Time:07-31

I am trying to learn more about array of objects. I have flatten array of objects and i am trying to nest it with levels when they have unique values. The thing is now i am using reduce, and getting new objects for each.

data = [
{ name1 : 'Tenis', id1: 1, name2: ATP, id2: 2, name3: Men Singles, id3: 4}
{ name1 : 'Tenis', id1: 1, name2: ATP, id2: 2, name3: Men Singles, id3: 4}
{ name1 : 'Tenis', id1: 1, name2: ATP, id2: 2, name3: Men Doubles, id3: 5}
{ name1 : 'Tenis', id1: 1, name2: WTA, id2: 3, name3: Women Doubles, id3: 6}
{ name1 : 'Tenis', id1: 1, name2: WTA, id2: 3, name3: Women Singles, id3: 7}
]

I want result to be:

result: [
 { sport: 'Tenis', 
   league: 
      [{ 
       ATP: [{ event: Men Singles, Men Doubles }]
       WTA: [{ event: Women Singles, Women Doubles   }]
      }]
}]

My code now:

const result = data.reduce((arr, item) => {
        if (arr.indexOf(item.name1) === -1) {
          arr.push({
            sport: item.name1 ,
            league: item.name2 ,
            event: item.name3 ,
          })
        }
        return arr
      }, [])

But i am getting every value:

0: {sportName: 'Tenis', league: 'ATP', event: 'Men Singles'}
1: {sportName: 'Tenis', league: 'WTA', event: 'Women Doubles'}
2: {sportName: 'Tenis', league: 'WTA', event: 'Women Doubles'}
.... etc

What i need to do, to obtain one nested object? I am literally blocked in mind.

CodePudding user response:

I definitely recommend not wrapping each object with an array

const data = [{ name1 : 'Tenis', id1: 1, name2: 'ATP', id2: 2, name3: 'Men Singles', id3: 4},{ name1 : 'Tenis', id1: 1, name2: 'ATP', id2: 2, name3: 'Men Singles', id3: 4},{ name1 : 'Tenis', id1: 1, name2: 'ATP', id2: 2, name3: 'Men Doubles', id3: 5},{ name1 : 'Tenis', id1: 1, name2: 'WTA', id2: 3, name3: 'Women Doubles', id3: 6},{ name1 : 'Tenis', id1: 1, name2: 'WTA', id2: 3, name3: 'Women Singles', id3: 7}]

const tranform = () => {
  const sport = data[0]['name1'];
  const league = data.reduce((r, e) => {
      r[e['name2']] ??= []
      if (!r[e['name2']].includes(e['name3'])) {                
        r[e['name2']].push(e['name3'])
      }
      return r;
  }, {});

  return { sport, league };
};
  
console.log(tranform())
.as-console-wrapper { max-height: 100% !important; top: 0 }

CodePudding user response:

You need to push to the specific inner arrays after checking if the value is already in there. We do this for the sport, then the league, then the event.

Note: I used an array for the events property.

data = [
{ name1 : 'Tenis', id1: 1, name2: 'ATP', id2: 2, name3: 'Men Singles', id3: 4},
{ name1 : 'Tenis', id1: 1, name2: 'ATP', id2: 2, name3: 'Men Singles', id3: 4},
{ name1 : 'Tenis', id1: 1, name2: 'ATP', id2: 2, name3: 'Men Doubles', id3: 5},
{ name1 : 'Tenis', id1: 1, name2: 'WTA', id2: 3, name3: 'Women Doubles', id3: 6},
{ name1 : 'Tenis', id1: 1, name2: 'WTA', id2: 3, name3: 'Women Singles', id3: 7}
]


const result = data.reduce((output, obj) => {
  // Sport Check - if not in, add the sport with the current league & event
  const sportObj = output.find(item => item.sport === obj.name1)
  if (!sportObj) {
    output.push( 
      { 
        sport: obj.name1,
        league: [{
          [obj.name2]: [{ events: [obj.name3] }]
         }] 
       })
    return output
  }
  // League Check - If not in, add a league to the sport with the current event
  const leagueObj = sportObj.league[0][obj.name2]
  if (!leagueObj) {
    sportObj.league[0][obj.name2] = [{ events: [obj.name3] }]
  } else {
    // Event Check - if not in, add the event. If not, don't do anything.
    const eventsArray = leagueObj[0].events
    if (!eventsArray.includes(obj.name3)) eventsArray.push(obj.name3)
  }
  return output
}, [])
 
 console.log(result)

  • Related