Repository navigation
按照以下要求,写一个数组(包含对象等类型元素)去重函数 #136
Copy link
Copy link
Open
Labels
Description
Activity
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; }// 不返回原数组元素
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 }解法:使用 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}]
Reacted by shadowkimi520, liuzb30, Showbuger and Ryan
如传入的数组元素为
[123, "meili", "123", "mogu", 123],则输出:[123, "meili", "123", "mogu"]如传入的数组元素为
[123, [1, 2, 3], [1, "2", 3], [1, 2, 3], "meili"],则输出:[123, [1, 2, 3], [1, "2", 3], "meili"]如传入的数组元素为
[123, {a: 1}, {a: {b: 1}}, {a: "1"}, {a: {b: 1}}, "meili"],则输出:[123, {a: 1}, {a: {b: 1}}, {a: "1"}, "meili"]