0

I have a problem with javascript code I have an array of the type

var array = [{
    name: "Name 1",
    id: 1
  },
  {
    name: "Name 2",
    id: 2
  },
  {
    name: "Name 3",
    id: 3
  },
  {
    name: "Name 1",
    id: 4
  },
  {
    name: "Name 1",
    id: 5
  },
  {
    name: "Name 2",
    id: 6
  },
];

I'd like to get this:

var newArray = [{
    name: "Name 1",
    id: [1, 4, 5]
  },
  {
    name: "Name 2",
    id: [2, 6]
  },
  {
    name: "Name 3",
    id: 3
  },
];

But I can't I tried with a .find() but it doesn't work Can you give me some leads please

VLAZ
  • 26,331
  • 9
  • 49
  • 67
Cohchi
  • 543
  • 3
  • 9
  • 19
  • Basically create a lookup-structure by your key field (seems to be `name` here) and put all your items there. Then just filter all lookup-entries by the number of items included. – Sirko Dec 19 '19 at 13:53
  • `find` seems pointless here--you need to iterate the original array, put each `name` into an object, adding the `id` to an initially-empty array, then take the new object and build an array out of its key-value pairs. – Dave Newton Dec 19 '19 at 13:54
  • So basically what you want is if there are more than one of the "same" objects then create an array of ids. If there's only one, leave the single value as a number. Am I correct? – Sebastian Kaczmarek Dec 19 '19 at 13:56
  • Also relevant: [Group array items using object](https://stackoverflow.com/questions/31688459/group-array-items-using-object) – VLAZ Dec 19 '19 at 13:58

4 Answers4

0

You can use reduce with a Map, for O(n) performance, as there are no nested loops:

const array = [
  { name: "Name 1", id: 1 },
  { name: "Name 2", id: 2 },
  { name: "Name 3", id: 3 },
  { name: "Name 1", id: 4 },
  { name: "Name 1", id: 5 },
  { name: "Name 2", id: 6 }
]

const out = [...array.reduce((a, o) => {
  const e = a.get(o.name)
  return (a.set(o.name, e ? Array.isArray(e) ? e.concat(o.id): [e, o.id] : o.id), a)
}, new Map())].map(([k, v]) => ({ name: k, id: v }))

console.log(out)
Kobe
  • 6,226
  • 1
  • 14
  • 35
0

You can use reduce() to create an object and then use Object.values to get an array. You can use map() after this to remove the array for those elements which have only a single id.

var array = [{
    name: "Name 1",
    id: 1
  },
  {
    name: "Name 2",
    id: 2
  },
  {
    name: "Name 3",
    id: 3
  },
  {
    name: "Name 1",
    id: 4
  },
  {
    name: "Name 1",
    id: 5
  },
  {
    name: "Name 2",
    id: 6
  },
];

const res = Object.values(array.reduce((ac, a) => {
  if(!ac[a.name]){
    ac[a.name] = {...a, id: []}
  }
  ac[a.name].id.push(a.id);
  return ac;
},{})).map(x => ({...x, id: x.id.length === 1 ? x.id[0] : x.id}))

console.log(res)
Maheer Ali
  • 35,834
  • 5
  • 42
  • 73
0

Try with Array.reduce() like this :

var array = [{
        name: "Name 1",
        id: 1
    },
    {
        name: "Name 2",
        id: 2
    },
    {
        name: "Name 3",
        id: 3
    },
    {
        name: "Name 1",
        id: 4
    },
    {
        name: "Name 1",
        id: 5
    },
    {
        name: "Name 2",
        id: 6
    },
];

var output = array.reduce((acc, current) => {
    if (exist = acc.find(p => p.name == current.name)) {
        if(!Array.isArray(exist.id)){
          exist.id = [exist.id];
        }
        exist.id.push(current.id);
    } else {

        acc.push(current)
    }
    return acc;
}, []);

console.log(output);
R.K.Saini
  • 2,678
  • 1
  • 18
  • 25
0

You can use .reduce() for that. This example produces exactly the same output you expect:

var array = [
  {
    name: "Name 1",
    id: 1
  },
  {
    name: "Name 2",
    id: 2
  },
  {
    name: "Name 3",
    id: 3
  },
  {
    name: "Name 1",
    id: 4
  },
  {
    name: "Name 1",
    id: 5
  },
  {
    name: "Name 2",
    id: 6
  }
];

var output = array.reduce(function(res, curr) {

  var existing = res.find(function(el) { return el.name === curr.name; });
  if (existing) {
    if (Array.isArray(existing.id))
      existing.id.push(curr.id);
    else
      existing.id = [existing.id, curr.id]
  } else {
    res.push(curr);
  }
  
  return res;
}, []);

console.log(output);
Sebastian Kaczmarek
  • 8,120
  • 4
  • 20
  • 38