108

I have a simple case of pushing unique values into array. It looks like this:

  this.items = [];

  add(item) {
    if(this.items.indexOf(item) > -1) {
      this.items.push(item);
      console.log(this.items);
    }
  }

Seems pretty straight-forward, right? No, as it appears. It doesn't add any values. I am sure it's some kind of silly mistake on my side, but I can't seem to find it.

Tomek Buszewski
  • 7,659
  • 14
  • 67
  • 112

15 Answers15

166

Yep, it's a small mistake.

if(this.items.indexOf(item) === -1) {
    this.items.push(item);
    console.log(this.items);
}
radbyx
  • 9,352
  • 21
  • 84
  • 127
Jagdish Idhate
  • 7,513
  • 9
  • 35
  • 51
90

You can use the Set structure from ES6 to make your code faster and more readable:

// Create Set
this.items = new Set();

add(item) {
    this.items.add(item);

    // Set to array
    console.log([...this.items]);
}
Community
  • 1
  • 1
Sergey Zhigalov
  • 1,019
  • 8
  • 3
  • @Gags not true, work on all major recent browsers. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set#Browser_compatibility – Abdul Rehman Nov 16 '18 at 07:50
  • 3
    As a heads up. If like me you use JSON.stringify in your code, adding Sets will cause issues without further updates. – John Duskin Jan 24 '19 at 16:48
  • 2
    I LOVE this. Had nearly forgotten about set. I'm going to be using this a lot, particularly nice in TypeScript. – Methodician Aug 27 '19 at 20:55
  • 2
    @JohnDuskin can you elaborate? Your comment might somehow suggest that using JSON.stringify in "your code", as in one scope?, with also using Set object, like even somewhere else in such scope/code? Or as more probable you mean using Set object as an argument to JSON.stringify. As in using them in one expression. [An issue described here](https://stackoverflow.com/questions/31190885/json-stringify-a-set) with solutions. – papo Apr 26 '21 at 15:44
  • 3
    @papo You're correct, on re-reading my comment it was a vague. You are correct in your interpretation, adding Sets to a JSON.stringify command causes issues (as per the issue you linked to) and the solution is that you need to convert it to an array. This can be more complex however if you are stringifying higher level objects that contain sets, so its something people should be aware of. – John Duskin Apr 27 '21 at 07:59
22

try .includes()

[1, 2, 3].includes(2);     // true
[1, 2, 3].includes(4);     // false
[1, 2, 3].includes(3, 3);  // false
[1, 2, 3].includes(3, -1); // true
[1, 2, NaN].includes(NaN); // true

so something like

const array = [1, 3];
if (!array.includes(2))
    array.push(2);

note the browser compatibility at the bottom of the page, however.

lachlan.p.jordan
  • 447
  • 5
  • 11
10

Using Set

this.items = new Set();
this.items.add(1);
this.items.add(2);
this.items.add(1);
this.items.add(2);

console.log(Array.from(this.items)); // [1, 2]
GMaiolo
  • 4,207
  • 1
  • 21
  • 37
Trilok Singh
  • 1,227
  • 12
  • 10
9

In case if you are looking for one liner

For primitives

(this.items.indexOf(item) === -1) && this.items.push(item);

For objects

this.items.findIndex((item: ItemType) => item.var === checkValue) === -1 && this.items.push(item);
talha2k
  • 24,937
  • 4
  • 62
  • 81
firoj_mujawar
  • 301
  • 4
  • 14
8

If you use Lodash, take a look at _.union function:

let items = [];
items = _.union([item], items)
xinthose
  • 3,213
  • 3
  • 40
  • 59
KitKit
  • 8,549
  • 12
  • 56
  • 82
7

Your logic is saying, "if this item exists already, then add it." It should be the opposite of that.

Change it to...

if (this.items.indexOf(item) == -1) {
    this.items.push(item);
}
ManoDestra
  • 6,325
  • 6
  • 26
  • 50
7

I guess ES6 has set data structure, which you can use for unique entries

Vivek Kumar
  • 4,822
  • 8
  • 51
  • 85
3

You have to use === -1, if it equals to -1 i.e. item is not available in your array:

  this.items = [];

  add(item) {
    if(this.items.indexOf(item) === -1) {
      this.items.push(item);
      console.log(this.items);
    }
  }
fdfey
  • 587
  • 2
  • 11
2

This can be achieved with single line of code.

this.items = this.items.includes(item) ? this.items : [...this.items, item];
Jitendra Tyagi
  • 173
  • 1
  • 6
2

Simple as possible!

  let items = [];
  const addItem = (item) => {
    items = [...new Set([...items, item])]
  };
Maged Mohamed
  • 752
  • 8
  • 7
1
var helper = {};
for(var i = 0; i < data.length; i++){
  helper[data[i]] = 1; // Fill object
}
var result = Object.keys(helper); // Unique items
1

Push always unique value in array

ab = [
     {"id":"1","val":"value1"},
     {"id":"2","val":"value2"},
     {"id":"3","val":"value3"}
   ];



var clickId = [];
var list = JSON.parse(ab);
$.each(list, function(index, value){
    if(clickId.indexOf(value.id) < 0){
        clickId.push(value.id);
    }
});
Rohit Agrohia
  • 368
  • 3
  • 7
0

so not sure if this answers your question but the indexOf the items you are adding keep returning -1. Not to familiar with js but it appears the items do that because they are not in the array yet. I made a jsfiddle of a little modified code for you.

this.items = [];

add(1);
add(2);
add(3);

document.write("added items to array");
document.write("<br>");
function  add(item) {
        //document.write(this.items.indexOf(item));
    if(this.items.indexOf(item) <= -1) {

      this.items.push(item);
      //document.write("Hello World!");
    }
}

document.write("array is : " + this.items);

https://jsfiddle.net/jmpalmisano/Lnommkbw/2/

jmp
  • 2,175
  • 2
  • 17
  • 16
0

Simple use new Set() with concat. The most performant mostly and updated:

console.log([...new Set(["hey", "we", "have", "array"].concat(["hey", "we", "add", "these", "too", "but without second hey, we, have :)"]))])

If you want to add elements in a case insensitive way, please do this for arrays;i.e:

["hey", "we", "HaVe", "ArrAy"].filter(r => r !== '').map(r => r.toUpperCase())

This will check whether empty element:

.filter(r => r !== '')

Will check case insensitive:

.map(r => r.toUpperCase()
Bitfinicon
  • 1,045
  • 1
  • 8
  • 22