skip to Main Content

Novice JS developer, need some help in identifying what I am doing wrong.

I have an array of objects

const ll = [{name:"a", ids:[1]}, {name:"b", ids:[2,3]}];

I want to convert it to following

[
  { name: 'a', ids: null, id: 1 },
  { name: 'b', ids: null, id: 2 },
  { name: 'b', ids: null, id: 3 }
]

essentially adding one record for each element in ids array.

This is the code I wrote

ll.reduce((r,o) => 
  r.concat(o.ids.map(i => {
       const r1 = o;
       r1.id = i;
       r1.ids = null;
       return r1;})),[])

What I am getting is

[
  { name: 'a', ids: null, id: 1 },
  { name: 'b', ids: null, id: 3 },
  { name: 'b', ids: null, id: 3 }
]

why 2 is missing & 3 is repeated?

Thanks in advance for your help on this.

3

Answers


  1. With const r1 = o, you are creating a reference to the original object o. Hence, when you modify r1.id and r1.ids, it affects all occurrences of r1 in the resulting array.

    Create a new object in each iteration and assign the properties individually. Also, you can optimized your code in the following way:

    const ll = [{name:"a", ids:[1]}, {name:"b", ids:[2,3]}];
    const res = ll.reduce((r,o) => 
      r.concat(o.ids.map(i => ({name: o.name, ids: null, id: i}))),[]);
           
    console.log(res);
    Login or Signup to reply.
  2. It seems to me the line const r1 = o; is causing the problem. The code assigns a reference to the variable o to r1, so when you modify r1, the original object o also change. Because the map function executes for each element in o.ids, the modifications to r1 affect the final result.

    To fix this issue, I believe you need to create a new object for each iteration of the map function. I guess you can just use the spread syntax (…) to create a shallow copy of the object. Below is a modification I did to your original code:

    const ll = [{name: "a", ids: [1]}, {name: "b", ids: [2, 3]}];
    
    const result = ll.reduce((r, o) => 
      r.concat(o.ids.map(i => ({
        ...o, // Shallow copy of the object
        id: i,
        ids: null
      }))), []);
    
    console.log(result);
    
    Login or Signup to reply.
  3. Here’s a solution using Array#flatMap():

    (A terser version can be found in the snippet below.)

    const result = ll.flatMap(object => {
      // For each original object
      return object.ids.map(id => {
        // ...create a new object for each id in it.
        const newObject = structuredClone(object);
    
        // Set .ids to null and assign id to .id.
        newObject.ids = null;
        newObject.id = id;
    
        return newObject;
      })
    });
    

    Try it:

    console.config({ maximize: true });
    
    const ll = [
      { name: "a", ids: [1] },
      { name: "b", ids: [2, 3] }
    ];
    
    const result = ll.flatMap(
      object => object.ids.map(
        id => Object.assign(structuredClone(object), { ids: null, id })
      )
    );
    
    console.log(result);
    <script src="https://gh-canon.github.io/stack-snippet-console/console.min.js"></script>
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search