Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JavaScript issue on using Array.includes() and test duplicate items

I have an input that uses an API to fetch some cities based on the letters inserted. The API is launched on each keyup event like so :

let ville_input = document.getElementById("search_immobilier_ville");
let ville_arr = [];

ville_input.addEventListener("keyup", () => {
  res_list.innerHTML = "";

  fetch("https://api.fr/communes?nom=" + ville_input.value)
    .then(res => {
      return res.json();
    })
    .then(data => {
      data.forEach(el => {
        if (
          el.codeDepartement == "971" &&
          el.nom
            .toUpperCase()
            .startsWith(ville_input.value.toUpperCase().trim())
        ) {
          if (!ville_arr.includes([el.nom, el.codesPostaux[0]])) {
            ville_arr.push([el.nom, el.codesPostaux[0]]);
            console.log(ville_arr);
          }
        }
      });
    })
    .catch(err => {
      // Doing stuff
    });
});

First of all I want to push each results as arrays into an array like so :

ville_arr.push([el.nom,el.codesPostaux[0]])

My issue is that I get duplicate items into my array when the API fetch the same result, that is why I tried this :

if(!ville_arr.includes([el.nom,el.codesPostaux[0]])){

    ville_arr.push([el.nom,el.codesPostaux[0]])
    console.log(ville_arr)

      }

But I still get duplicate items in the end, I guess it has something to do with the indexes of the array which are unique ? maybe something else ?

Here's a result example

like image 837
naspy971 Avatar asked May 18 '26 13:05

naspy971


2 Answers

Array.prototype.includes does a referential equality check for objects.

This means that, even though you are pushing objects of the same shape, they are not the same references because each request creates a new object.

The usual pattern is to remember some uniquely identifying part of an object instead, like an id.

Maybe you can store and check for the zipcode instead?

if (!zipcodes.includes(el.codesPostaux[0])) {
  zipcodes.push(el.codesPostaux[0]);
  ville_arr.push([el.nom, el.codesPostaux[0]]);
}

A time-efficient method is to use a set of zipcodes instead of an array (because set lookup time is O(1)):

if (!zipcodesSet.has(el.codesPostaux[0])) {
  zipcodesSet.add(el.codesPostaux[0]);
  ville_arr.push([el.nom, el.codesPostaux[0]]);
}

If you decide to use the ville_arr only, then what you need could also be done using Array.prototype.every (or Array.prototype.some):

// this will return true if every place in ville_arr
// does not have the zipcode from the response
if (ville_arr.every(([, zipcode]) => zipcode !== el.codesPostaux[0])) {
  ville_arr.push([el.nom, el.codesPostaux[0]]);
}

You could also potentially call JSON.stringify over your object to create the same string from a certain object and save that which would work because includes does equality comparison for primitive values such as strings.

like image 174
nem035 Avatar answered May 20 '26 03:05

nem035


Try this:

const ville_input = document.getElementById('search_immobilier_ville');
let ville_arr = [];
ville_input.addEventListener('keyup', () => {
    res_list.innerHTML = '';

    fetch(`https://api.fr/communes?nom=${ville_input.value}`)
        .then(res => {

            // Clear old data if get new response
            ville_arr = [];

            return res.json();
        })
        .then(...)
        .catch(...);
});

OR try use Array.prototype.find() (and extra info about find vs some on jsPerf.com):

if(!ville_arr.find(i => i[1] === el.codesPostaux[0])) {

    ville_arr.push([el.nom, el.codesPostaux[0]]);
    console.log(ville_arr);
}
like image 28
Slaawwa Avatar answered May 20 '26 03:05

Slaawwa



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!