Using Reduce To Flatten My Duplicate Object Array

IDEA: Trying to figure out the proper way to flatten my array to be grouped by the ID and the value can be in an array for nickName:

Example:

  1. This is my starting array=> [
    {id:1,nickName:“greatest1337”},
    {id:1,nickName:“Bob”},
    {id:2,nickName:“notReallyCool”},
    ]
  2. Need to figure out how to do a reduce function to reduce this to =>
    [
    {id:1,nickName:[“greatest1337”,“Bob”]},
    {id:2,nickName:[“notReallyCool”]}
    ]

What have you tried so far? You can use reduce to do this, though I would start out by making the reduce create an object and then convert that object into an array.

I’ve tried

objectArray.reduce(()=>{
  if (!o[i.id]) o[i.id] = [];
  o[i.id].push(i);

  return o;
},{})

but it returns something like this:
{
1: [
{id:1,nickName:“greatest1337”},
{id:1,nickName:“Bob”},
],
2:[
{id:2,nickName:“notReallyCool”}
]
}

It gives me my grouping, but I need it to be an array object. I realize right now it starts as an object but this is as close as I could get :frowning:

I’ve edited your post for readability. When you enter a code block into a forum post, please precede it with a separate line of three backticks and follow it with a separate line of three backticks to make it easier to read.

You can also use the “preformatted text” tool in the editor (</>) to add backticks around text.

See this post to find the backtick on your keyboard.
Note: Backticks (`) are not single quotes (’).

So sorry, I saw that instantly and tried to change but you beat me to it. :sweat_smile:

Cool, that’s exactly how I would have started too. (Though, I would have used clearer variable names so its easier for you to remember what you did when you look at this in the future. I always need to leave breadcrumbs for myself.).

From here, there is some magic

let myObj = {
  dog: 5,
  cat: 6,
};
console.log(Object.values(myObj));

Thank you for your insight, I still haven’t got the structure I need though, I just wanted to elaborate that.

Did you try the code I posted? It makes an array.

Ah, woops, the contents aren’t quite right. I’d modify the sub-objects in your reduce to match what you need. I’m on my phone but I can elaborate more later.

Yeah, sorry that’s not helping me with this particular situation. I already have an a javascript array. However, my problem is I need to merge the nick names with the ID being unique instead of duplicate IDs

You 'll need that part eventually because you are turning the array into an object and will need to convert back to array.

The change you need to make is minor. Your reduce is making {id, [{id, nickName}]}. You want instead {id, {id, [nickName]}}.

I’m sorry, I’m not following

You’re making an array of duplicates. You need to instead extract the nicknames from the duplicates and make an array of them.

I’ m sorry, I am trying everything.

What would I need to change in this code?:

const objectArray = [
  {id:1,nickName:"greatest1337"},
  {id:1,nickName:"Bob"},
  {id:2,nickName:"notReallyCool"},
  ];
const test = objectArray.reduce((o,i)=>{
  if (!o[i.id]) o[i.id] = [];
  o[i.id].push(i);

  return o;
},{})

This is where you make the array of duplicates. This looks like

[
  {id:1,nickName:"greatest1337"},
  {id:1,nickName:"Bob"},
]

You want to rearrange this so you have

{
  id: 1,
  nickName: ["greatest1337", "Bob"],
}

To do this, you’ll need to change

This to be an object that matches the form above with an empty nicknames array and

this part to push only the nicknames to the nicknames array.

Thank you for your guidance Jeremy. Really appreciate it. I will try to figure it out from here.

Let us know if you have more questions. Like I said, I’m on my phone, so my response is a bit messy and other people might have clearer suggestions.

1 Like

So, you want to flatten this array:

const arr = [
  { id: 1, nickName: "greatest1337" },
  { id: 1, nickName: "Bob" },
  { id: 2, nickName: "notReallyCool" },
];

into this array:

[
  { id: 1, nickName: ["greatest1337", "Bob"] },
  { id: 2, nickName: ["notReallyCool"] },
];

First, as the desired result is an array, the initial value of the accumulator must be an empty array:

arr.reduce((newArr, currentObj) => {
  
}, []);

Next, we need to check, with the filter method, if our accumulator, the newArr, contains an object with the same id as currentObj. For the sake of clarity, let’s use object destructuring on currentObj to get its properties:

arr.reduce((newArr, { id, nickName }) => {
  let objWithSameId = newArr.filter((obj) => obj.id === id);

  }
}, []);

objectWithSameId will be an empty array, if the current object is the first with its id processed. Otherwise, objectWithSameId will be an array with only one object.

So, we check its length. If it is 0, we return newArr concatenated with a new object. Otherwise, we push the new nickname to the existing object:

arr.reduce((newArr, { id, nickName }) => {
  let objWithSameId = newArr.filter((obj) => obj.id === id);

  if (objWithSameId.length === 0) {
    return newArr.concat({
      id,
      nickName: [nickName],
    });
  } else {
    objWithSameId[0].nickName.push(nickName);
    return newArr;
  }
}, []);

I won’t lie, I had a headache trying to solve this!!! :yum::+1:

Welcome to the forum!

I added spoiler tags to the solution. We like to add them on the forum so the OP has the option to ‘cover up the answer’ and only peak if they really want to.


FWIW, this is how I’d do it:

// Hash map of condensed entries
flattenedHashmap = arr.reduce(
  (hashmap, { id: currentId, nickName: currentName }) => {
    // Add id if not found
    if (!hashmap[currentId])
      hashmap[currentId] = {
        currentId: { id: currentId, nickName: [] }
      };
    // Add nickname to array
    hashmap[currentId].nickName.push(currentName);
    // Return hashmap for next elem
    return hashmap
  }, {});
// Strip out array of values
flattenedArray = Object.values(flattenedHashmap);

Using a hashmap structure saves on the back and forth of searching through the new array as you reduce.

1 Like