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

Posted

技术标签:

【中文标题】使用 Array.includes() 和测试重复项的 JavaScript 问题【英文标题】:JavaScript issue on using Array.includes() and test duplicate items 【发布时间】:2019-05-24 05:39:19 【问题描述】:

我有一个输入,它使用 API 根据插入的字母来获取一些城市。 API 在每个 keyup 事件上启动,如下所示:

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)

      

但我最后还是得到了重复的项目,我想这与数组的索引是唯一的有关吗?也许还有别的?

【问题讨论】:

【参考方案1】:

Array.prototype.includes 对对象进行引用相等检查。

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

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

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

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

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

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

如果您决定只使用ville_arr,那么您也可以使用Array.prototype.every(或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]]);

您还可以通过您的对象调用JSON.stringify 以从某个对象创建相同的字符串并保存可以使用的字符串,因为includes 对字符串等原始值进行相等比较。

【讨论】:

【参考方案2】:

试试这个:

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

【讨论】:

【参考方案3】:

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)

【讨论】:

【参考方案4】:

另一种“老派”的做法可能是:声明一个对象 (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()

【讨论】:

以上是关于使用 Array.includes() 和测试重复项的 JavaScript 问题的主要内容,如果未能解决你的问题,请参考以下文章

array.includes的使用

Array.includes 在 html 文件上传和 localforage 中无法正常工作

浏览器支持 array.includes 和替代品

array.includes 使用正则表达式返回 false

javascript array.includes在反应中不起作用

如何为 JS Array.includes() 提供 equals/hash 函数? [复制]