使用 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 在 html 文件上传和 localforage 中无法正常工作
array.includes 使用正则表达式返回 false