高效处理数据问题

找一个高效处理数据的算法

let arr1 = [{
    name: 'online'
}, {
    name: 'offline'
}]

let arr2 = [{
    id: 1,
    name: ['online']
}, {
    id: 2,
    name: ['online', 'offline']
}]


function merge(arr1, arr2) {
    // ...
}
let arr3 = merge(arr1, arr2)
/*
arr3结构
 [{
    name: 'online',
    ids: [1, 2]
}, {
    name: 'offline',
    ids: [2]
}]
O(n)
*/

求一个时间复杂度最小的实现, 可直接改变arr1数组到arr3状态,实际的数据量很大,数组还有其他很多属性

补充:要实现的功能是在根据arr1中的name属性在arr2中过滤出对于的id,然后记录下来。求个最优解

阅读 2.5k
5 个回答

这是一个把 arr1 当作规则数组的处理方法,

function merge(arr1, arr2) {
    const match = (rules => {
        const keys = Object.keys(rules[0]);

        return function (it) {
            return rules.filter(rule => {
                return keys.every(k => {
                    const v = rule[k];
                    const value = it[k];
                    return Array.isArray(value)
                        ? value.includes(v)
                        : value === v;
                });
            });
        };
    })(arr1);

    function mergeIt(source, target) {
        source.ids ??= [];
        source.ids.push(target.id);
    }

    arr2.forEach(it => {
        match(it).forEach(rule => mergeIt(rule, it));
    });
    return arr1;
}

但是,貌似题主的意思是 arr1 其实也有数据,只有 name 是规则,那么……

function merge(target, source) {
    source.forEach(it => {
        target.forEach(t => {
            if (it.name.includes(t.name)) {
                t.ids ??= [];
                t.ids.push(it.id);
            }
        })
    });
    return target;
}

这两句话需要较新的 ES 环境

t.ids ??= [];
t.ids.push(...);

可以改为旧语法的

(t.ids || (t.ids = [])).push(...);

我写了一个,但是感觉还差点意思

function merge(arr1, arr2) {
    arr1.forEach(item => {
        if(!Array.isArray(item.ids)) {
            item.ids = []
        }
        const target = arr2.filter(it => Array.isArray(it.name) && it.name.includes(item.name))

        if(Array.isArray(target) && target.length) {
            let ids =target.map(j => j.id)
            item.ids = item.ids.concat(ids)
        }

    })
    return arr1
}
function merge(arr1, arr2) {
    let obj = arr2.reduce((obj, item) => {
        item.name.forEach(citem => {
            (obj[citem] = obj[citem] || []).push(item.id)
        })
        return obj
    }, {})
    arr1.forEach(item => {
        item.ids = obj[item.name] || []
    })
    return arr1
}

尝试了一下

function merge(arr1, arr2) {
  const temp = arr1.reduce((cur, item) => {
    const obj = {};
    obj['name'] = item.name;
    obj['ids'] = []
    arr2.forEach((sub)=>{
      if(sub.name.includes(item.name)){
        obj.ids.push(sub.id)
      }
    })
    cur.push(obj);
    return cur;
  }, []);
  return temp
}

这个最简单,只需要arr2就可以了

const arr = [{
            id: 1,
            name: ['online']
        }, {
            id: 2,
            name: ['online', 'offline']
        }]
        let obj = {}
        arr.forEach(item => {
            item.name.forEach(v => {
                if(!obj[v]) obj[v] = []
                obj[v].push(item.id)
            })
        })
        console.log(Object.keys(obj).map(item => {
            return {
                name: item,
                ids: obj[item]
            }
        }))
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题
宣传栏