手写一个数组(包含对象等类型元素)去重函数

我们之前看过了 手写数组去重、扁平化函数 ,以及 不产生新数组,删除数组里的重复元素 ,这里再次加深一下,如果是数组元素包含对象等类型,又该如何去重喃?

示例如下:

  1. 如传入的数组元素为 [123, "meili", "123", "mogu", 123] ,则输出: [123, "meili", "123", "mogu"]

  2. 如传入的数组元素为 [123, [1, 2, 3], [1, "2", 3], [1, 2, 3], "meili"] ,则输出: [123, [1, 2, 3], [1, "2", 3], "meili"]

  3. 如传入的数组元素为 [123, {a: 1}, {a: {b: 1}}, {a: "1"}, {a: {b: 1}}, "meili"] ,则输出: [123, {a: 1}, {a: {b: 1}}, {a: "1"}, "meili"]

可以自己思考一下,再看以下解答????

基础:JSON.stringify 去重

我们最先想到的是使用 JSON.stringify 去重

const removeDuplicates = (arr) => {
    let map = new Map()
    arr.forEach(item => {
        map.set(JSON.stringify(item), item)
    })
    return [...map.values()]
}

// 测试
removeDuplicates([123, "meili", "123", "mogu", 123])
// [123, "meili", "123", "mogu"]
removeDuplicates([123, [1, 2, 3], [1, "2", 3], [1, 2, 3], "meili"])
// [123, [1, 2, 3], [1, "2", 3], "meili"]
removeDuplicates([123, {a: 1}, {a: {b: 1}}, {a: "1"}, {a: {b: 1}}, "meili"])
// [123, {a: 1}, a: {b: 1}, {a: "1"}, "meili"]

深入一下

使用 JSON.stringify ,如果数组元素是 object 类型且里面键的顺序不同则会认为是两个不同放入数组元素

let o1 = {a:1, b:2}
let o2 = {b:2, a:1}
JSON.stringify(o1)
// "{"a":1,"b":2}"
JSON.stringify(o2)
// "{"b":2,"a":1}"
JSON.stringify(o1) === JSON.stringify(o2)
// false

这种问题该如何解决喃?

解决思路:

一个数组(包含对象等类型元素)去重函数,需要在基础类型判断相等条件下满足以下条件:

  • 如果元素是数组类型,则需要数组中的每一项相等

  • 如果元素是对象类型,则需要对象中的每个键值对相等

去重本身就是遍历数组,然后比较数组中的每一项是否相等而已,所以关键步骤有两步:比较、去重

比较:

  • 首先判断类型是否一致,类型不一致则返回认为两个数组元素是不同的,否则继续

  • 如果是数组类型,则递归比较数组中的每个元素是否相等

  • 如果是对象类型,则递归比较对象中的每个键值对是否相等

  • 否则,直接 === 比较

去重:

  • 采用 reduce 去重,初始 accumulator 为 []

  • 采用 findIndex 找到 accumulator 是否包含相同元素,如果不包含则加入,否则不加入

  • 返回最终的 accumulator ,则为去重后的数组

代码实现:

// 获取类型
const getType = (function() {
    const class2type = { '[object Boolean]': 'boolean', '[object Number]': 'number', '[object String]': 'string', '[object Function]': 'function', '[object Array]': 'array', '[object Date]': 'date', '[object RegExp]': 'regexp', '[object Object]': 'object', '[object Error]': 'error', '[object Symbol]': 'symbol' }

    return function getType(obj) {
        if (obj == null) {
            return obj + ''
        }
        // javascript高级程序设计中提供了一种方法,可以通用的来判断原始数据类型和引用数据类型
        const str = Object.prototype.toString.call(obj)
        return typeof obj === 'object' || typeof obj === 'function' ? class2type[str] || 'object' : typeof obj
    };
})();

/**
 * 判断两个元素是否相等
 * @param {any} o1 比较元素
 * @param {any} o2 其他元素
 * @returns {Boolean} 是否相等
 */
const isEqual = (o1, o2) => {
    const t1 = getType(o1)
    const t2 = getType(o2)

    // 比较类型是否一致
    if (t1 !== t2) return false
    
    // 类型一致
    if (t1 === 'array') {
        // 首先判断数组包含元素个数是否相等
        if (o1.length !== o2.length) return false 
        // 比较两个数组中的每个元素
        return o1.every((item, i) => {
            // return item === target
            return isEqual(item, o2[i])
        })
    }

    if (t2 === 'object') {
        // object类型比较类似数组
        const keysArr = Object.keys(o1)
        if (keysArr.length !== Object.keys(o2).length) return false
        // 比较每一个元素
        return keysArr.every(k => {
            return isEqual(o1[k], o2[k])
        })
    }

    return o1 === o2
}

// 数组去重
const removeDuplicates = (arr) => {
    return arr.reduce((accumulator, current) => {
        const hasIndex = accumulator.findIndex(item => isEqual(current, item))
        if (hasIndex === -1) {
            accumulator.push(current)
        }
        return accumulator
    }, [])
}

// 测试
removeDuplicates([123, {a: 1}, {a: {b: 1}}, {a: "1"}, {a: {b: 1}}, "meili", {a:1, b:2}, {b:2, a:1}])
// [123, {a: 1}, a: {b: 1}, {a: "1"}, "meili", {a: 1, b: 2}]

最后

欢迎关注「三分钟学前端」,回复「交流」自动加入前端三分钟进阶群,每日一道编程算法面试题(含解答),助力你成为更优秀的前端开发!

另外,每周还有手写源码题,瓶子君也会解答哟!

》》面试官也在看的前端面试资料《《

“在看和转发”就是最大的支持

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值