2

Getting data from graphql, example:

const data = [
  {
    items: [
      {
        link: '/monday',
        name: 'Monday',
      },
      {
        link: '/tuesday',
        name: 'Tuesday',
      },
      {
        link: '/wednesday',
        name: 'Wednesday',
      },
    ],
  },
  {
    items: [
      {
        link: '/january',
        name: 'January',
      },
      {
        link: '/february',
        name: 'February',
      },
      {
        link: '/march',
        name: 'March',
      },
    ],
  },
]

I'm trying to build a new object and also add a unique id but it takes me two loops to accomplish (also includes expected output):

  const data = [
    {
      items: [
        {
          link: '/monday',
          name: 'Monday',
        },
        {
          link: '/tuesday',
          name: 'Tuesday',
        },
        {
          link: '/wednesday',
          name: 'Wednesday',
        },
      ],
    },
    {
      items: [
        {
          link: '/january',
          name: 'January',
        },
        {
          link: '/february',
          name: 'February',
        },
        {
          link: '/march',
          name: 'March',
        },
      ],
    },
  ]
  
  let itemsObj = []
  let merge = []

  data.forEach(section => {
    section.items.forEach((item, i) => {
      return (itemsObj = [...itemsObj, item])
    })
  })

  itemsObj.map((item, i) => {
    item.id = i
    return merge.push(item)
  })
  
  console.log(itemsObj)

Code that correctly builds what I need but takes a foreach and map:

data.forEach(section => {
  section.items.forEach((item, i) => {
    return (itemsObj = [...itemsObj, item])
  })
})

itemsObj.map((item, i) => {
  item.id = i
  return merge.push(item)
})

When I try to add an incremented id in one loop it starts over, example:

const data = [
  {
    items: [
      {
        link: '/monday',
        name: 'Monday',
      },
      {
        link: '/tuesday',
        name: 'Tuesday',
      },
      {
        link: '/wednesday',
        name: 'Wednesday',
      },
    ],
  },
  {
    items: [
      {
        link: '/january',
        name: 'January',
      },
      {
        link: '/february',
        name: 'February',
      },
      {
        link: '/march',
        name: 'March',
      },
    ],
  },
]

 let itemsObj = []

  data.forEach(section => {
    section.items.forEach((item, i) => {
      item.id = i
      return (itemsObj = [...itemsObj, item])
    })
  })
  
  console.log(itemsObj)

Code trying to add the id and build the object in one loop that causes the id to start over:

let itemsObj = []

data.forEach(section => {
  section.items.forEach((item, i) => {
    item.id = i
    return (itemsObj = [...itemsObj, item])
  })
})

console.log(itemsObj)

Per answer same issue occurs with an id that isn't unique:

data.flatMap(dataObj => {
  return dataObj.items.map((item, i) => {
    return { i, ...item }
  })
})

Expected output example to clarify comment:

[
  {
    "link": "/monday",
    "name": "Monday",
    "id": 0
  },
  {
    "link": "/tuesday",
    "name": "Tuesday",
    "id": 1
  },
  {
    "link": "/wednesday",
    "name": "Wednesday",
    "id": 2
  },
  {
    "link": "/january",
    "name": "January",
    "id": 3
  },
  {
    "link": "/february",
    "name": "February",
    "id": 4
  },
  {
    "link": "/march",
    "name": "March",
    "id": 5
  }
]

Research:

Is there a way to an id in one loop instead of using a foreach and map?

4
  • 1
    What’s your expected output? Commented Jun 6, 2021 at 15:42
  • @decpk the above ran example where there is a foreach and map loop? Commented Jun 6, 2021 at 15:42
  • What do you mean by one loop as in the second code block you are still using the nested loops. Commented Jun 6, 2021 at 15:43
  • edited question with code snippets. Commented Jun 6, 2021 at 15:47

3 Answers 3

3

You can create a variable outside of flatMap and increment after it gets added to end result.

You can even make it a one-liner if you'd like

const result = data.flatMap(({ items }) =>  items.map((item) => ({ i: start++, ...item })));

1) With flatMap

const data = [
  {
    items: [
      {
        link: "/monday",
        name: "Monday",
      },
      {
        link: "/tuesday",
        name: "Tuesday",
      },
      {
        link: "/wednesday",
        name: "Wednesday",
      },
    ],
  },
  {
    items: [
      {
        link: "/january",
        name: "January",
      },
      {
        link: "/february",
        name: "February",
      },
      {
        link: "/march",
        name: "March",
      },
    ],
  },
];

let start = 0;
const result = data.flatMap(({ items }) => {
  return items.map((item) => {
    return { i: start++, ...item };
  });
});

console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

2) With reduce

const data = [
  {
    items: [
      {
        link: "/monday",
        name: "Monday",
      },
      {
        link: "/tuesday",
        name: "Tuesday",
      },
      {
        link: "/wednesday",
        name: "Wednesday",
      },
    ],
  },
  {
    items: [
      {
        link: "/january",
        name: "January",
      },
      {
        link: "/february",
        name: "February",
      },
      {
        link: "/march",
        name: "March",
      },
    ],
  },
];

const result = data.reduce((acc, { items }, index) => {
  return [
    ...acc,
    ...items.map((o, i) => ({ i: acc.length * index + i, ...o })),
  ];
}, []);

console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Sign up to request clarification or add additional context in comments.

5 Comments

Thanks never used flatmap so learned something new.
For performance which should be used, reduce or flatmap?
There is no much difference in performance, You can use anyone. It just came in my mind so I shared it, so that It can help you to understand better...
It is the unique value that you should take away from my answer i.e i: acc.length * index + i
@DᴀʀᴛʜVᴀᴅᴇʀ - Note to the OP. This is still multiple loops - it's just now a little more hidden. There is no way to iterate an array of objects each with their own array without multiple loops.
1

Try flatMap

let index = 0
data.flatMap(dataObj => {
  return dataObj.items.map((item) => {
    return { i: index++, ...item }
  })
})

Comments

0
let itemsObj = []
let index = 0;

data.forEach(section => {
  section.items.forEach((item) => {
    item.id = index;
    index++;
    return (itemsObj = [...itemsObj, item])
  })
})

console.log(itemsObj)

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.