1

I'm trying to prevent an object getting added to an array more than once if it already exists. From what I gather online, I can use the indexOf of method to compare a value, but in my test, items still get added to my array regardless of whether they exist?

What am I doing wrong?

function getRndInteger(min = 1, max = 5, step = 1) {
  const range = (max - min) / step
  return Math.floor(Math.random() * range) * step + min
}

const items = []
let obj = {
  content: "<p></p>"
}

setInterval(() => {
  const random = getRndInteger(1, 3)
  obj = {
    content: `<p>hello world ${random}</p>`
  }

  if (items.indexOf(obj.content) === -1) items.push(obj)
  console.log(items)
}, 1000)

If an item in my array has another item with exactly the same content, then I want to prevent adding it again, why doesn't this work?

Here's a JS fiddle as well -> https://jsfiddle.net/mxLcyjo8/1/

Thanks!

Not A Bot
  • 2,474
  • 2
  • 16
  • 33
Ryan H
  • 2,620
  • 4
  • 37
  • 109
  • You store `obj` in `items` but you're searching for `obj.content`. How should this work? – Andreas Mar 30 '21 at 12:37
  • `obj` is a representation of my structure containing `content`, in reality this would come from a user. So they click a button and their item is pushed into an array, if they create a new item with exactly the same then `obj.content` (the new item) needs to be compared against the array and prevent it from adding. – Ryan H Mar 30 '21 at 12:40
  • Use [`find`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/find), which takes a function, rather than `indexOf`. – Heretic Monkey Mar 30 '21 at 12:40
  • That might be the case, but how or why should `.indexOf()` be aware of the internals of those `obj`s you store in `items`? – Andreas Mar 30 '21 at 12:42
  • why not `if( ! items.includes(obj))` ? – giulp Mar 30 '21 at 12:42
  • Does this answer your question? [How do I check if an array includes a value in JavaScript?](https://stackoverflow.com/questions/237104/how-do-i-check-if-an-array-includes-a-value-in-javascript) – Heretic Monkey Mar 30 '21 at 12:42
  • `!items.includes(obj)` does not work because now I've got two array items added to my array which contain `

    hello world 1

    `, which isn't right. I need to exclude duplicate objects form my array
    – Ryan H Mar 30 '21 at 12:45
  • I do not have an array, I have an array of objects, so doing a simple check with that `.includes('jane')` does not work because it can't scan the objects in the array – Ryan H Mar 30 '21 at 12:46
  • indeed :) `if(! items.find(o => o.content === obj.content))` – giulp Mar 30 '21 at 12:49

1 Answers1

0

Instead of an array, use a map and index your objects by content. That ensures no duplicate at cheap lookups.

You can then get the array of items back by convertng Map#values().

function getRndInteger(min = 1, max = 5, step = 1) {
  const range = (max - min) / step
  return Math.floor(Math.random() * range) * step + min
}

const map = new Map();

setInterval(() => {
  const random = getRndInteger(1, 3)
  const obj = {
    content: `<p>hello world ${random}</p>`
  }

  if (!map.has(obj.content)) map.set(obj.content, obj)

  const items = Array.from(map.values());
  console.log(items)
}, 1000)

Alternatively, if you want to keep an array available at all times, instead of creating it on demand, you could use a set to store unique values and add obj to your array only if there is a disparity in the count. This would work if the interval is the only thing that changes the items, because then you can be sure that the count can only differ by one at a time - if the set has one more unique item. If so, obj can be added to the array.

function getRndInteger(min = 1, max = 5, step = 1) {
  const range = (max - min) / step
  return Math.floor(Math.random() * range) * step + min
}

const lookup = new Set();
const items = [];

setInterval(() => {
  const random = getRndInteger(1, 3)
  const obj = {
    content: `<p>hello world ${random}</p>`
  }
  
  lookup.add(obj.content);
  
  if (lookup.size !== items.length) 
    items.push(obj)

  console.log(items)
}, 1000)
VLAZ
  • 26,331
  • 9
  • 49
  • 67