Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

按照以下要求,写一个数组(包含对象等类型元素)去重函数 #136

Open
sisterAn opened this issue Dec 8, 2020 · 3 comments

Comments

@sisterAn
Copy link
Owner

sisterAn commented Dec 8, 2020

  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"]

@chengjianguo1
Copy link

function duplicate(list) {
    if (!list) {
        return;
    }
    const map = new Map();
    const newArr = [];
    list.forEach(item => {
        if (!map.has(item)) {
            if (typeof item === 'string' || typeof item === 'number') {
                map.set(item, item);
                newArr.push(item);
            } else if (!map.has(JSON.stringify(item))) {
                map.set(JSON.stringify(item), item);
                newArr.push(item);
            }
        }
    });
    return newArr;
}

@shadowkimi520
Copy link

// 不返回原数组元素

function removeDuplicates(arr) {
  if (!Array.isArray(arr)) {
    return []
  }
  const set = new Set(arr.map(item => JSON.stringify(item)))
  return [...set].map(item => JSON.parse(item))
}

// 返回原数组元素

function removeDuplicates(arr) {
  const result = []
  if (!Array.isArray(arr)) {
    return result
  }
  const set = new Set()
  arr.forEach(item => {
    if (!set.has(JSON.stringify(item))) {
      set.add(JSON.stringify(item))
      result.push(item)
    }
  })
  return result
}

@sisterAn
Copy link
Owner Author

sisterAn commented Dec 9, 2020

解法:使用 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}]

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants