0

I have this simple array:

const arr = [
  {
    "id": 2,
    "color": "red"
  },
  {
    "id": 1,
    "color": "blue"
  },
  {
    "id": 2,
    "color": "yellow"
  },
];

I want to create a hash map where I want to add new colors on that key.

E.g I want to added color: green on id: 3

Now here you can see there is no id: 3

Now here I am expecting:

{
    2: [{color: "red"}]
    1: [{color: "blue"}, {color: "yellow"}],
    3: [{color: "green"}]
}

Now if I want to add color: brown on id: 2

In that case I am expecting:

{
    2: [{color: "red"}, {color: "brown"}]
    1: [{color: "blue"}, {color: "yellow"}],
    3: [{color: "green"}]
}

I have created a Playground:

const arr = [
  {
    "id": 2,
    "color": "red"
  },
  {
    "id": 1,
    "color": "blue"
  },
  {
    "id": 2,
    "color": "yellow"
  },
];

function addItem(id: number, colors: any) {
    let newArr = {[id]: colors};
  arr.forEach(function (obj) {

    newArr[obj.id].push({id: obj.color});
  });
  return newArr;
}

console.log(addItem(3, [{color: "green"}]))
console.log(addItem(1, [{color: "brown"}]))

Here I also want to avoid duplicates

StormTrooper
  • 1,731
  • 4
  • 23
  • 37
  • Not sure to understand what you want, but I think you need a simple Map: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map – Mario Vernari Dec 01 '22 at 15:42
  • SO has a snippet function (`[<>]`) you can use to embed your code in the question rather than sending people to a 3rd-party site to view the code. – Andy Dec 01 '22 at 15:43
  • 1
    @Andy Could you check now – StormTrooper Dec 01 '22 at 15:47
  • 1
    It looks like you want to group the first array by `id`? see [How can I group an array of objects by key?](https://stackoverflow.com/questions/40774697/how-can-i-group-an-array-of-objects-by-key) – pilchard Dec 01 '22 at 15:59
  • @pilchard could you modify my snippet? – StormTrooper Dec 01 '22 at 16:05
  • OP, where do you want to avoid duplicates? Just in the array you're adding in the new colour, or are you checking all of the arrays? – Andy Dec 01 '22 at 17:04
  • In both keys and and colors should be unique im each array against key – StormTrooper Dec 01 '22 at 17:46
  • There shouldn't be 2 keys with id: 1 in main object, and there should be single {color: red} against id: 1 – StormTrooper Dec 01 '22 at 17:50

5 Answers5

1

const arr = [{
    "id": 2,
    "color": "red"
  },
  {
    "id": 1,
    "color": "blue"
  },
  {
    "id": 2,
    "color": "yellow"
  },
];

const grouped = arr.reduce((groups, current) => {
  if (!(current.id in groups)) {
    groups[current.id] = []
  }
  groups[current.id].push({
    color: current.color
  })
  return groups
}, {})

addItem(3, {
  color: "green"
})

addItem(1, {
  color: "brown"
})

console.log(grouped)

function addItem(id, item) {
  if (!(id in grouped)) {
    grouped[id] = []
  }
  grouped[id].push(item)
}
Konrad
  • 21,590
  • 4
  • 28
  • 64
  • I need a very short and optimized answer for that – StormTrooper Dec 01 '22 at 16:21
  • Konrad has the correct approach @StormTrooper - grouping the data into an object first, and then writing a function to update the object. It's not really clear what you're looking for at the moment. – Andy Dec 01 '22 at 17:54
0
function test(id, color) {
                for (var i = 0; i < arr.length; i++) {
                  if (arr[i].id == id) {
                    arr[i].color.push(color)
                  }
                }
              }

Basically it will loop through your array, and if its id matches, it will add your color.

ACTS 238
  • 26
  • 1
0

Following code can help you to solve this problem

const hashMap = new Map([
  [1, [{ color: "red" }]],
  [2, [{ color: "blue" }]],
  [3, [{ color: "yellow" }]],
]);

function addItem(id, colors) {
  hashMap.set(
    id,
    hashMap.has(id) ? [...hashMap.get(id).concat(colors)] : colors
  );

  return hashMap;
}
console.log(hashMap);
console.log(addItem(3, [{ color: "green" }]));
console.log(addItem(4, [{ color: "pink" }]));
  • Does this solve the problem of avoiding duplicates as mentioned at the bottom of the question? – Andy Dec 01 '22 at 17:03
0

let arr = [{
    "id": 2,
    "color": "red"
  },
  {
    "id": 1,
    "color": "blue"
  },
  {
    "id": 2,
    "color": "yellow"
  },
];

const groupBy = (xs, key) => {
  return xs.reduce(function(rv, x) {
    const y = {...x};
    delete y[key];
    (rv[x[key]] = rv[x[key]] || []).push(y);
    return rv
  }, {})
}


const addItem = (id, colors) => {
  // const newArr = arr... etc if you don't want to modify the existing array
  arr = arr.concat(colors.map(c => {
    c.id = id;
    return c
  }))

  const grouped = groupBy(arr, 'id')
  return grouped
}

console.log(addItem(3, [{
  color: "green"
}]))
console.log(addItem(1, [{
  color: "brown"
}]))
dangarfield
  • 2,210
  • 1
  • 13
  • 18
0

You may find a class useful here to encapsulate your data.

  1. On initialisation pass in your array of objects and convert it to a Map with array values. (Note: you can use an object here as an alternative).

  2. Create a method that adds new colours to the appropriate map array if they don't already exist (i.e. testing for duplicates).

const arr=[{id:2,color:"red"},{id:1,color:"blue"},{id:2,color:"yellow"}];

class ColorMap {
        
  // `reduce` over the array to create a `colors` Map.
  // If the id doesn't exist on the map as a key,
  // create it, and assign an empty array to it.
  // Then push in the color to the array if
  // it doesn't already exist
  constructor(arr) {
    this.colors = arr.reduce((acc, obj) => {
      const { id, color } = obj;
      if (!acc.has(id)) acc.set(id, []);
      if (!this.colorExists(id, color)) {
        acc.get(id).push({ color });
      }
      return acc;
    }, new Map());
  }
  
  // Simple check to see if the color already
  // exists in the target array
  colorExists(id, color) {
    return this.colors?.get(id)?.find(obj => {
      return obj.color === color;
    });
  }

  // Similar to the `reduce` function, if the id doesn't have
  // a key on the map create one, and initialise an empty array,
  // and if the color doesn't already exist add it
  addColor(id, color) {
    if (!this.colors.has(id)) this.colors.set(id, []);
    if (!this.colorExists(id, color)) {
      this.colors.get(id).push({ color });
    }
  }

  // Return the colors map as a readable object
  showColors() {
    return Object.fromEntries(this.colors);
  }

}

const colorMap = new ColorMap(arr);

colorMap.addColor(3, 'green');
colorMap.addColor(1, 'brown');
colorMap.addColor(1, 'brown');

console.log(colorMap.showColors());

Additional documentation

Andy
  • 61,948
  • 13
  • 68
  • 95