返回

JavaScript 数组比较:获取匹配 ID 对象的 Name 值

javascript

JavaScript 中比较两个数组并从第二个数组获取匹配记录

这问题问的...比较抽象啊。简单来说,就是要根据第一个数组里的 ID,从第二个数组里找出对应 ID 的对象,然后提取出这些对象的 name 属性,组成一个新的数组。

问题原因

原代码的错误在于使用了 find 方法,而且比较的方式不对。find 方法只会返回 第一个 满足条件的元素,而且在循环里直接拿 array1 的元素跟 array2id 属性比较,逻辑上就不对。 你需要遍历 array1,然后对于每个元素,都要在 array2 里面找对应 id 的对象。

解决方案

1. 使用 filter + map (推荐)

这是最简洁明了的方案,可读性高,也容易理解。

  • 原理:
    1. 先用 filter 方法过滤 array2,找出所有 id 属性存在于 array1 中的对象。
    2. 再用 map 方法将过滤后的对象数组转换为只包含 name 属性的数组。
  • 代码示例:
var array1 = [2, 10];
var array2 = [
    { id: 1, name: 'robin' },
    { id: 2, name: 'david' },
    { id: 3, name: 'john' },
    { id: 6, name: 'vinay' },
    { id: 10, name: 'ramdin' },
    { id: 15, name: 'vin' },
];

const result = array2
    .filter(item => array1.includes(item.id))
    .map(item => item.name);

console.log(result); // 输出: ['david', 'ramdin']
  • 进阶技巧:
    如果 array1 很大,可以使用 Set 来提高 includes 的效率。
    var array1 = [2, 10];
    const array1Set = new Set(array1); // 转换为 Set
    var array2 = [
        { id: 1, name: 'robin' },
        { id: 2, name: 'david' },
        { id: 3, name: 'john' },
        { id: 6, name: 'vinay' },
        { id: 10, name: 'ramdin' },
        { id: 15, name: 'vin' },
    ];
    
    const result = array2
        .filter(item => array1Set.has(item.id)) // 使用 has 方法
        .map(item => item.name);
    
    console.log(result);
    
    Sethas 方法查找比数组的 includes 方法快,尤其是在数组很大的时候。

2. 使用 reduce

reduce 方法能一行代码搞定,但可读性稍微差点。

  • 原理: reduce 遍历 array2,对每个元素进行判断,如果 idarray1 中,就把 name 属性添加到累加器数组里。
  • 代码示例:
var array1 = [2, 10];
var array2 = [
    { id: 1, name: 'robin' },
    { id: 2, name: 'david' },
    { id: 3, name: 'john' },
    { id: 6, name: 'vinay' },
    { id: 10, name: 'ramdin' },
    { id: 15, name: 'vin' },
];

const result = array2.reduce((acc, item) => {
    if (array1.includes(item.id)) {
        acc.push(item.name);
    }
    return acc;
}, []);

console.log(result); // 输出: ['david', 'ramdin']
  • 进阶技巧 : 同样,如果array1非常大,也可以将其转为Set来优化includes

    var array1 = [2, 10];
    const array1Set = new Set(array1);
    var array2 = [
        { id: 1, name: 'robin' },
        { id: 2, name: 'david' },
        { id: 3, name: 'john' },
        { id: 6, name: 'vinay' },
        { id: 10, name: 'ramdin' },
        { id: 15, name: 'vin' },
    ];
    
    const result = array2.reduce((acc, item) => {
        if (array1Set.has(item.id)) {
            acc.push(item.name);
        }
        return acc;
    }, []);
    
    console.log(result);
    

3. 使用双重循环 (不推荐)

双重循环虽然能解决问题,但效率最低,代码也比较啰嗦。

  • 原理: 外层循环遍历 array1,内层循环遍历 array2,逐个比较 id
  • 代码示例:
var array1 = [2, 10];
var array2 = [
    { id: 1, name: 'robin' },
    { id: 2, name: 'david' },
    { id: 3, name: 'john' },
    { id: 6, name: 'vinay' },
    { id: 10, name: 'ramdin' },
    { id: 15, name: 'vin' },
];

const result = [];
for (let i = 0; i < array1.length; i++) {
    for (let j = 0; j < array2.length; j++) {
        if (array1[i] === array2[j].id) {
            result.push(array2[j].name);
            break; // 找到了就跳出内层循环
        }
    }
}

console.log(result); // 输出: ['david', 'ramdin']
  • 可以考虑使用forEach使代码稍微简洁一点。

4. 先构建array2的Map,再查询 (处理大量数据)

  • 原理: 如果 array2 非常大,或者需要进行多次这样的查询,可以先构建一个 idname 的映射(Map),这样查询的时候就不用每次都遍历 array2 了。

  • 代码:

var array1 = [2, 10];
var array2 = [
    { id: 1, name: 'robin' },
    { id: 2, name: 'david' },
    { id: 3, name: 'john' },
    { id: 6, name: 'vinay' },
    { id: 10, name: 'ramdin' },
    { id: 15, name: 'vin' },
];

const idToNameMap = new Map(array2.map(item => [item.id, item.name]));
const result = array1.map(id => idToNameMap.get(id)).filter(name => name !== undefined);

console.log(result); // 输出: ['david', 'ramdin']

  • 解释:

    1. new Map(array2.map(item => [item.id, item.name])):把array2转化成一个Map,其中键(key)是id,值(value)是name
    2. array1.map(id => idToNameMap.get(id)):对array1中的每个id,去Map里取对应的name。如果id不存在,get方法返回 undefined
    3. .filter(name => name !== undefined) 把上一步中产生的 undefined 值过滤掉。
  • 额外说明: 这种方法的优势在于,如果 array2 很大,并且你需要根据 array1 里的不同 ID 值进行多次查询,那么只需要构建一次 Map,后续查询就会非常快。

总结

选择哪个方法取决于你的具体需求:

  • 如果要代码简单,可读性好,就用 filter + map
  • 如果要追求极致简洁(但牺牲一点可读性),用 reduce
  • 不要用双重循环,效率太低。
  • 如果 array2 非常大,或者要进行多次查询,先构建 Map。
    尽量避免在循环内部做复杂的操作或者使用性能较差的方法,影响网页或者服务器响应。