0

I have an object that looks like the following:

const test = {
  leagues: [
    {
      timezone: "GMT",
      date: "1/2/2",
      premierLeague: [
        { name: "Liverpool", age: 1892 },
        { name: "Manchester Utd", age: 1878 }
      ],
      laLiga: [
        {
          team: "Real Madrid",
          stadium: "Bernabeu"
        },
        {
          team: "Barcelona",
          stadium: "Camp Nou"
        }
      ]
    }
  ]
};

and I want the result to look like

const result = [
  { name: "Liverpool", age: 1892 },
  { name: "Manchester Utd", age: 1878 },
  {
    team: "Real Madrid",
    stadium: "Bernabeu"
  },
  {
    team: "Barcelona",
    stadium: "Camp Nou"
  }
];

I have tried to use flat() but am having trouble getting the arrays within the leagues. The result will be dynamic so I need to be able to get all the arrays within leagues. Can anyone point me in the correct direction to do this?

4
  • 3
    Do you really want that result? It's objects of totally different shapes in the same array. Don't do that. Commented May 9, 2022 at 20:19
  • I know it's not ideal, but it is what I need Commented May 9, 2022 at 20:19
  • Check the solutions here, it may help stackoverflow.com/questions/27266550/… Commented May 9, 2022 at 20:20
  • @Evren Not sure how that can help, please be more specific how you think it will help Commented May 9, 2022 at 20:21

4 Answers 4

3

If your object structure doesn't go an deeper than that, this long one-liner should work:

const result = test.leagues.reduce((arr, obj) => Object.values(val).reduce((innerArr, val) => Array.isArray(val) ? innerArr.concat(val) : innerArr, arr), []);

Somewhat ungolfed:

const result = test.leagues.reduce((arr, obj) => {
  return Object.values(val).reduce((innerArr, val) => {
    return Array.isArray(val)
      ? innerArr.concat(val) 
      : innerArr
  }, arr);
}), []);
Sign up to request clarification or add additional context in comments.

5 Comments

Mixing reduce with forEach and push is quite ugly, don't you think?
@Bergi you're not wrong. I fired that off between meetings
Thanks! I'd still prefer @Juan's for+push or my flatMap over reduce, but at least it's consistent now :-)
I almost deleted my answer since I saw this and @Bergi's . I still posted it in because the double loop is the easiest one to scan and quickly know what is happening. I do know it is not as elegant 😊
@JuanMendes don't sweat it. Elegant is a matter of degrees.
2

You might be looking for

const result = test.leagues.flatMap(league =>
  Object.values(league).filter(Array.isArray).flat()
);

2 Comments

thanks for this, but as I said the response will be dynamic so can't hard code names of the arrays
@peterflanagan Oh I thought you would know the structure, and only the values in the arrays would be dynamic… but if you don't know the names of array-valued properties I have updated my answer. It still assumes test.leagues to be an array of objects with possibly-array-valued properties, is that right? Not arbitrarily nested?
1

This sounds weird, you'll end up with objects of different shapes in the same array. I'm not sure how you'll deal with that.

It looks like you're trying to concatenate every value of test.leagues that is itself an array.

const test = {
  leagues: [{
    timezone: "GMT",
    date: "1/2/2",
    premierLeague: [{
        name: "Liverpool",
        age: 1892
      },
      {
        name: "Manchester Utd",
        age: 1878
      }
    ],
    laLiga: [{
        team: "Real Madrid",
        stadium: "Bernabeu"
      },
      {
        team: "Barcelona",
        stadium: "Camp Nou"
      }
    ]
  }]
};


const output = [];
for (const league of test.leagues) {
  for (const key in league) {
    if (Array.isArray(league[key])) {
      // Push each element in `league[key]` onto `output`
      // so we don't have to flatten it later
      output.push(...league[key]);
    }
  }
}
console.log({
  output
});

2 Comments

this isn't actually what I want. It should be a flat array
@peterflanagan Fixed by spreading the arrays as we push them: output.push(...league[key]);
0

Well, I'm also adding my 2 cents over here. I do agree with everyone else. See if this works:

const test = {
  leagues: [
    {
      timezone: "GMT",
      date: "1/2/2",
      premierLeague: [
        { name: "Liverpool", age: 1892 },
        { name: "Manchester Utd", age: 1878 }
      ],
      laLiga: [
        {
          team: "Real Madrid",
          stadium: "Bernabeu"
        },
        {
          team: "Barcelona",
          stadium: "Camp Nou"
        }
      ]
    }
  ]
};

let finalArray = [];

function recursiveArr(obj, arrayToPush) {
    for(const [key, val] of Object.entries(obj)) {
    if(Array.isArray(obj[key])) {
      arrayToPush.push(obj[key]);
      continue;
    }
    
    const type = typeof obj[key];
    
    if(type === "object") {
       recursiveArr(obj[key], arrayToPush);
    }
  }
}

recursiveArr(test.leagues, finalArray);

console.log(finalArray.flat())

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.