Flutter中对比两个数组获取目标optid的实现方案(含非循环方法)
如何高效匹配两个数组的ID以获取对应的optid?
问题背景
我手头有两个数组,需要通过对比它们的id值,找到对应的optid。具体来说:
第一个数组(咱们叫它optArray)的结构是这样的:
[ { "optid": "20", "ids": [ { "id": "16", "desc": "test 1" }, { "id": "12", "optionCode": "test 2" }, { "id": "6", "optionCode": "test 3" } ] }, { "optid": "22", "ids": [ { "id": "20", "desc": "test 1" }, { "id": "15", "optionCode": "test 2" }, { "id": "6", "optionCode": "test 3" } ] }, { "optid": "23", "ids": [ { "id": "17", "desc": "test 1" }, { "id": "2", "optionCode": "test 2" }, { "id": "6", "optionCode": "test 3" } ] } ]
第二个数组(targetIdsArray)是:
[ { "id": 17, "name": "test 1" }, { "id": 2, "name": "test 2" }, { "id": 6, "name": "tes t3" } ]
我的目标是找到**ids列表完全匹配第二个数组所有id**的那个optid(这里预期结果是23)。我知道嵌套循环能实现,但想找更高效的方案,有没有更好的办法?
优化方案推荐
核心思路是利用哈希结构(Set/Map)把查找复杂度从O(n)降到O(1),避免嵌套循环带来的性能浪费,尤其是数据量大的时候效果很明显。
方案1:单次查询最优——用Set快速校验匹配
先把目标数组的id转成字符串类型的Set(注意第一个数组里的id是字符串,第二个是数字,得统一类型),然后遍历optArray,检查每个元素的ids是否和目标Set完全匹配:
// 第一步:把目标ID转成字符串Set,方便快速查找 const targetIdSet = new Set(targetIdsArray.map(item => String(item.id))); // 第二步:遍历optArray找匹配项 const matchedOptid = optArray.find(optItem => { // 把当前opt项的所有id也转成Set const optIdSet = new Set(optItem.ids.map(idItem => idItem.id)); // 两个Set完全相等的条件:大小一致,且目标Set的所有元素都在当前Set里 return optIdSet.size === targetIdSet.size && [...targetIdSet].every(id => optIdSet.has(id)); })?.optid; console.log(matchedOptid); // 输出:"23"
这种方式的时间复杂度是O(n + m),比嵌套循环的O(n*m)高效很多。
方案2:多次查询最优——预构建映射表
如果需要多次做这类匹配查询,建议先提前构建一个optid到对应id集合的映射表,之后每次查询都能直接快速匹配:
// 预处理:构建optid到id集合的映射 const optIdMap = new Map(); optArray.forEach(optItem => { const idSet = new Set(optItem.ids.map(idItem => idItem.id)); optIdMap.set(optItem.optid, idSet); }); // 处理目标ID集合 const targetIdSet = new Set(targetIdsArray.map(item => String(item.id))); // 查找匹配的optid let matchedOptid = null; for (const [optid, idSet] of optIdMap) { if (idSet.size === targetIdSet.size && [...targetIdSet].every(id => idSet.has(id))) { matchedOptid = optid; break; } } console.log(matchedOptid); // 输出:"23"
预处理只需要做一次,后续每次查询的成本都很低,适合频繁查询的场景。
方案3:简洁写法(小数据量适用)
如果数据量很小,也可以用更直观的写法,虽然效率不如前两种,但胜在代码简洁:
const targetIds = targetIdsArray.map(item => String(item.id)); const matchedOptid = optArray.find(optItem => { const optIds = optItem.ids.map(idItem => idItem.id); // 校验长度一致,且所有目标ID都在当前opt的ids里 return targetIds.length === optIds.length && targetIds.every(id => optIds.includes(id)); })?.optid;
不过includes是O(n)的操作,数据量大的时候性能会下降,所以只推荐小数据场景用。
总结
- 单次查询选方案1,兼顾效率和代码简洁度;
- 多次查询选方案2,预处理一次后后续查询成本极低;
- 小数据量可以用方案3,代码更直观。
内容的提问来源于stack exchange,提问作者vellai durai
相关产品推荐
相关产品推荐

