使用Array.includes()和测试重复项的JavaScript问题

时间:2018-12-25 16:17:44

标签: javascript arrays ajax fetch

我有一个输入,该输入使用API​​根据插入的字母提取某些城市。每次keyup事件都会启动该API,如下所示:

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
    });
});

首先,我想将每个结果作为数组推送到像这样的数组中:

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

我的问题是,当API获取相同的结果时,我将重复的项放入数组中,这就是为什么我尝试这样做:

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

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

      }

但是最后我仍然得到重复的项目,我想这与唯一的数组索引有关吗?也许还有其他东西吗?

Here's a result example

4 个答案:

答案 0 :(得分:4)

Array.prototype.includes对对象进行参照相等性检查。

这意味着,即使您要推挤相同形状的对象,它们也不是相同的引用,因为每个请求都会创建一个新对象。

通常的模式是记住对象的某些唯一标识部分,例如ID。

也许您可以存储并检查邮政编码?

req1 = url.urlopen("url")
url.urlretrieve(req1.geturl(),"excelfile.xls")

info = req1.info()
print(info.get_content_type()) 

time.sleep(5)

req2 = url.urlopen("url")
url.urlretrieve(req2.geturl(),"excelfile.xls")

info = req2.info()
print(info.get_content_type())

一种省时的方法是使用一组邮政编码而不是一个数组(因为设置的查找时间为O(1)):

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

如果您决定仅使用if (!zipcodesSet.has(el.codesPostaux[0])) { zipcodesSet.add(el.codesPostaux[0]); ville_arr.push([el.nom, el.codesPostaux[0]]); } ,则还可以使用Array.prototype.every(或Array.prototype.some)来完成所需的操作:

ville_arr

您还可以潜在地在对象上调用// 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]]); } ,以从某个对象创建相同的字符串,并保存可行的字符串,因为JSON.stringify对字符串之类的原始值进行相等比较。

答案 1 :(得分:1)

尝试一下:

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(...);
});

或尝试使用Array.prototype.find()(以及jsPerf.com上有关find vs some的其他信息):

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

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

答案 2 :(得分:1)

Array#includes不会通过引用类型的值比较引用类型;它比较它们以检查它们的引用是否相同。

例如,这将产生false

var myArr = [[5, 6], [1, 2], [4, 5]];

console.log(myArr.includes([1, 2]));  // false

因为第1行的[1, 2]数组与第3行的数组不同,即使它们包含相同的值。

要解决此问题,您可以改用Array#some,它接受​​一个lambda函数:

var myArr = [[5, 6], [1, 2], [4, 5]];

console.log(myArr.some(e => e[0] === 1 && e[1] === 2));  // true

或者根据您的具体示例进行说明:

if(!ville_arr.some(e => e[0] === el.nom && e[1] === el.codesPostaux[0])) {
    ville_arr.push([el.nom,el.codesPostaux[0]])
    console.log(ville_arr)
}

答案 3 :(得分:1)

另一种“古老的”做法是:声明一个对象(o),并使用从每个数组的内容生成的密钥向其添加子数组。然后,该对象将自行保留其唯一结构:

var o={d:{},add:function(nom,code){this.d[nom+code]=[nom,code]},
get:function(){return Object.values(this.d)}};

您可以通过添加值

o.add(el.nom, el.codePosteaux[0]);

并使用

从中检索唯一数组
o.get()