3

我有一个输入,它使用 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)

      }

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

这是一个结果示例

4

4 回答 4

4

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对原始值(例如字符串)进行相等比较。

于 2018-12-25T16:27:54.227 回答
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() (以及有关find 与jsPerf.com 上的某些内容的额外信息):

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

    ville_arr.push([el.nom, el.codesPostaux[0]]);
    console.log(ville_arr);
}
于 2018-12-25T16:26:28.743 回答
1

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

例如,这会产生false

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

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

因为第[1, 2]1 行的数组与第 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)
}
于 2018-12-25T16:31:02.503 回答
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()
于 2018-12-25T17:20:20.297 回答