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

第 113 题:根据以下要求,写一个数组去重函数 #215

Open
yygmind opened this issue Jul 25, 2019 · 83 comments
Open

第 113 题:根据以下要求,写一个数组去重函数 #215

yygmind opened this issue Jul 25, 2019 · 83 comments

Comments

@yygmind
Copy link
Contributor

yygmind commented Jul 25, 2019

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

@liuwenai
Copy link

我不会🙁

@Nina0408
Copy link

用set做

@Ficks
Copy link

Ficks commented Jul 25, 2019

 ̄□ ̄||

@SilvaYH
Copy link

SilvaYH commented Jul 25, 2019

function parseArr(arr){
return [...new Set(arr.map(JSON.stringify))].map(JSON.parse)
}

没有考虑到数据类型为null,undefind等类型 包括数据为对象时key顺序不同的问题
这里再更正一下
// 判断对象
function isObj(obj){
 return Object.prototype.toString.call(obj) === '[object Object]'
}
// 对象重整 对key进行排序
function parseObj(obj){
	let keys = Object.keys(obj).sort()
	let newObj = {}
	for(let key of keys){
               // 不晓得有没有有必要,反正把value为obj的情况也处理一下 - -
                obj[key]=isObj(obj[key])?parseObj(obj[key]):obj[key]
		newObj[key] = obj[key]
	}
	return newObj
}

// 最后
const arr = [1,'1',{a:1,b:"1"},{b:'1',a:1},{a:1,b:2},[1,2,3],null,undefined,undefined]
function passArr(arr){
	return [...new Set(arr.map(item=>
		isObj(item)? JSON.stringify(parseObj(item)) : ( !item ? item : JSON.stringify(item))
    ))].map(item=>!item?item : JSON.parse(item))
}

@MarioJames
Copy link

用set做的麻烦问一下怎么处理对象顺序不同的问题
如{a:1, b:2}和{b:2, a: 1}

@MoveZZG
Copy link

MoveZZG commented Jul 25, 2019

NO Set

arr.map(JSON.stringify).filter((v, k, arr) => arr.indexOf(v) === k).map(JSON.parse)

@flyfox11
Copy link

flyfox11 commented Jul 25, 2019

用JSON.parse和JSON.stringify的同学,如果数组有undefined是不是就报错了;还有就是如果数组里包含循环引用的对象,是不是就都报错了╮(╯▽╰)╭

@suguoyao
Copy link

suguoyao commented Jul 25, 2019

用JSON.stringify的,没考虑object里的key顺序不同?😑做题前要把情况考虑清楚
image

@Gentlemancj
Copy link

function dis(arr) {
    const resObj = {};
    const res = [];
    arr.forEach((item) => {
        const key = item + JSON.stringify(item);
        if (!resObj[key]) {
            res.push(item);
            resObj[key] = item;
        }
    })
    return res;
}

const test1 = [123, "meili", "123", "mogu", 123];

const test2 = [123, [1, 2, 3], [1, "2", 3], [1, 2, 3], "meili"];

const test3 = [123, { a: 1 }, { a: { b: 1 } }, { a: "1" }, { a: { b: 1 } }, "meili"];

console.log(dis(test1));

console.log(dis(test2));

console.log(dis(test3));

@ZodiacSyndicate
Copy link

ZodiacSyndicate commented Jul 25, 2019

自定义哈希函数 哈希表

因为JSON.stringify碰到key顺序不同但值相同的对象时生成的字符串不一样,所以自定义哈希函数,处理对象时先把对象的key按字典序排序,然后再生成哈希字符串

function hash(arg) {
    if (typeof arg === 'string') return `"${arg}"`
    if (typeof arg === 'number' || typeof arg === 'undefined') return `${arg}`
    if (typeof arg === 'symbol' || typeof arg === 'boolean') return arg.toString()
    if (arg === null) return 'null'
    if (Array.isArray(arg)) {
        let res = '['
        for (const item of arg) {
            res += `${hash(item)},`
        }
        res += ']'
        return res
    }
    let res = '{'
    const keys = Object.keys(arg).sort()
    for (const key of keys) {
        res += `${key}:${hash(arg[key])},`
    }
    res += '}'
    return res
}

function distinct(arr) {
    const res = []
    const map = {}
    for (const item of arr) {
        const key = hash(item)
        if (!map[key]) {
            map[key] = 1
            res.push(item)
        }
    }
    return res
}

@IAMSBLOL
Copy link

IAMSBLOL commented Jul 25, 2019

    var addSign = (data) => {
        
        var signArr = data.map((o, i) => {
            return JSON.stringify(o)
        })

        var set = [...new Set(signArr)]

        return set.map((o, i) => JSON.parse(o))
    }

//这个还要做类型判断和还原的,但是我们可以机智的用JSON.stringify它帮我们做了不同类型的处理
### 保留一下先,key顺序不同会出问题。不能是完全解决

案例测试:
addSign([123, "meili", "123", "mogu", 123]);
image

addSign([123, [1, 2, 3], [1, "2", 3], [1, 2, 3], "meili"]);
image

addSign([123, {a: 1}, {a: {b: 1}}, {a: "1"}, {a: {b: 1}}, "meili"]);
image

addSign([123, {a: 1}, {a: {b: 1}}, {a: "1"}, {a: {b: [1,2,{a:2222}]}}, "meili"]);
image

@pangxieju
Copy link

pangxieju commented Jul 25, 2019

var $ = {
filters1: function(data) {
if (!data || !data.length) return [];

var temp = {0: [], 1: []};
for (var i = 0; i < data.length; i++) {
  if (!~temp[0].indexOf(JSON.stringify(data[i]))) {
    temp[0].push(JSON.stringify(data[i]))
    temp[1].push(data[i]);
  }
}
return temp[1];

},
filters2: function(data) {
if (!data || !data.length) return [];

var temp = {};
for (var i = 0; i < data.length; i++) {
  temp[JSON.stringify(data[i])] = data[i];
}
return Object.values(temp);

},
filters3: function(data) {
if (!data || !data.length) return [];

var d = new Map();
for (var i = 0; i < data.length; i++) {
  d.set(JSON.stringify(data[i]), data[i]);
}

var temp = [];
d.forEach(val => {
  temp.push(val);
})

return temp;

},
filters4: function(data) {
if (!data || !data.length) return [];

return data.map(JSON.stringify).filter((v, k, data) => data.indexOf(v) === k).map(JSON.parse);

},
filters5: function(data) {
if (!data || !data.length) return [];

return [...new Set(data.map(JSON.stringify))].map(JSON.parse);

}
};

  • 2 输出的顺序会不一致
  • 4,5 数组里有 undefined 会报错
  • 使用 JSON.stringify 只是为了保证唯一值来去重
  • 其实不用 JSON.stringify 也可以实现,比如取 MD5
  • 如果错误欢迎指正

@harryliuy
Copy link

harryliuy commented Jul 25, 2019

let arr = [123, "meili", "123", "mogu", 123];
let _arr = [];
arr.forEach(it => {
    if (!_arr.some(v => _.isEqual(v,it))) {
        _arr.push(it);
    }
});
console.log(_arr);

lodash

@chenweihuan
Copy link

最原始(ben)的方式,两个for循环

var a=[123, [1, 2, 3], [1, "2", 3], [1, 2, 3], "meili"];
function fn(arr) {
	let res =[];
	arr.forEach(v=>{
		if(res.length === 0){
			res.push(v);
		}else{
			for(let i =0;i<=res.length;i++){
				if(JSON.stringify(res[i]) === JSON.stringify(v))break;
				if(i === res.length-1)res.push(v);
			}
		}
	})
	return res;
}
console.log(fn(a));//[123, [1, 2, 3], [1, "2", 3], "meili"]

@suguoyao
Copy link

suguoyao commented Jul 25, 2019

var toType = (obj) => {
  return ({}).toString.call(obj).match(/\s([a-zA-Z]+)/)[1].toLowerCase()
}

var isEqual = (value, other) => {
  var type = toType(value);
  if (type !== toType(other)) return false;

  if (type === 'number') {
    return value === other
  }

  var valueLen = type === 'array' ? value.length : Object.keys(value).length;
  var otherLen = type === 'array' ? other.length : Object.keys(other).length;
  if (valueLen !== otherLen) return false;

  if (type === 'array') {
    for (var i = 0; i < valueLen; i++) {
      if (!isEqual(value[i], other[i])) return false;
    }
  } else {
    for (var key in value) {
      if (value.hasOwnProperty(key)) {
        if (!isEqual(value[key], other[key])) return false;
      }
    }
  }

  return true;
};


function unique(arr) {
  arr = arr.reduce((previous, current) => {

    var object = previous.filter(item => isEqual(item, current));
    if (object.length === 0) {
      previous.push(current);
    }
    return previous;
  }, []);
  return arr
}

unique([123, {a: 1}, {a: {c: 1, b: 1}}, {a: "1"}, {a: {b: 1, c: 1}}, "meili"])
// => [ 123, { a: 1 }, { a: { c: 1, b: 1 } }, { a: '1' }, 'meili' ]

@nowgoant
Copy link

function filterArray(array) {
  var keys = {}
  if (array && array.length) {
    var rst = array.filter((val1)=>{
      var str = JSON.stringify(val1);
      if (!keys[str]) {
        keys[str] = true;
        return true;
      } else {
        return false;
      }
    })
  }

  return rst;
}
// [123, "meili", "123", "mogu", 123],则输出:[123, "meili", "123", "mogu"]
console.log(filterArray([123, "meili", "123", "mogu", 123]))
// [123, [1, 2, 3], [1, "2", 3], [1, 2, 3], "meili"],则输出:[123, [1, 2, 3], [1, "2", 3], "meili"]
console.log(filterArray([123, [1, 2, 3], [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"]
console.log(filterArray([123, {a: 1}, {a: {b: 1}}, {a: "1"}, {a: {b: 1}}, "meili"]))

@ZTrainWilliams
Copy link

ZTrainWilliams commented Jul 25, 2019

function filterMap (arr) {
    var Map103 = new Map()
    arr.forEach(item => {
        Map103.set(JSON.stringify(item), item)
    })
    return [...Map103.values()]
}
console.log(filterMap([123, "meili", "123", "mogu", 123]))
console.log(filterMap([123, [1, 2, 3], [1, "2", 3], [1, 2, 3], "meili"]))
console.log(filterMap([123, {a: 1}, {a: {b: 1}}, {a: "1"}, {a: {b: 1}}, "meili"]))

@yeyan1996
Copy link

let x = [123, "meili", "123", "mogu", 123]
let x1 = [123, [1, 2, 3], [1, "2", 3], [1, 2, 3], "meili"]
let x2 = [123, {a: 1}, {a: {b: 1}}, {a: "1"}, {a: {b: 1}}, "meili"]



function func(arr) {
    let newArr = arr.map(item => JSON.stringify(item))
    return arr.filter((item,index)=>{
        if(typeof item === 'object') {
            return newArr.indexOf(JSON.stringify(item)) === index
        }else{
            return arr.indexOf(item) === index
        }
    })
}

console.log(func(x))
console.log(func(x1))
console.log(func(x2))

考点就在于2个一模一样对象的过滤,虽然是一样的,但是会作为不同的对象存储在堆内存中,所以需要用JSON.stringify 序列化才能准确判断,逻辑方面没有5楼写的好

@weiweixuan
Copy link

let arr1 = [123, 'meili', '123', 'mogu', 123]
      let arr2 = [123, [1, 2, 3], [1, '2', 3], [1, 2, 3], 'meili']
      let arr3 = [
        123,
        { a: 1 },
        { a: { b: 1 } },
        { a: '1' },
        { a: { b: 1 } },
        'meili'
      ]
      function repeat(arr) {
        if (!Array.isArray(arr)) {
          throw new TypeError('请输入数组···')
        }
        return [...new Set(arr.map(item => JSON.stringify(item)))].map(item =>
          JSON.parse(item)
        )
      }
      let res1 = repeat(arr1)
      let res2 = repeat(arr2)
      let res3 = repeat(arr3)
      console.log(res1) //[123, "meili", "123", "mogu"]
      console.log(res2) //[123, [1, 2, 3], [1, "2", 3], "meili"]
      console.log(res3) //[123, {a: 1}, {a: {b: 1}}, {a: "1"}, "meili"]

@fengtomy
Copy link

const _toString = Object.prototype.toString;
const looseEqual = (a, b) => {
  if (a === b) {
    return true;
  }
  const typeA = _toString.call(a);
  const typeB = _toString.call(b);
  if (typeA === "[object Object]") {
    if (typeB === "[object Object]") {
      let flag = true;
      for (let prop in a) {
        if (a.hasOwnProperty(prop) && b.hasOwnProperty(prop)) {
          flag = looseEqual(a[prop], b[prop]);
        } else {
          flag = false;
          break;
        }
      }
      return flag;
    } else {
      return false;
    }
  }
  if (typeA === "[object Array]") {
    if (typeB === "[object Array]") {
      if (a.length !== b.length) {
        return false;
      }
      let flag = true;
      for (let i = 0; i < a.length; i++) {
        if (!looseEqual(a[i], b[i])) {
          flag = false;
          break;
        }
      }
      return flag;
    } else {
      return false;
    }
  }
  // string number boolean undefined null, exclude regexp, date, symbol, set, map, weakMap, weakSet
  return a === b;
};
const arr = [123, {a: 1}, {a: {b: 1}}, {a: "1"}, {a: {b: 1}}, "meili"];
const looseIncludes = (arr, item) => {
  let flag = false;
  for (let i = 0; i < arr.length; i++) {
    if (looseEqual(arr[i], item)) {
      return flag = true;
    }
  }
  return flag;
};
const result = arr.reduce((a, b) => {
  if (looseIncludes(a, b)) {
    return a;
  }
  return [...a, b];
},[]);
console.log(result);

@EnergySUD
Copy link

function removal(arr){
	let obj = {},key,newArr=[];
	for(let i = 0;i<arr.length;i++){
		key = JSON.stringify(arr[i]);
		if(!obj[key]){
			obj[key] = key;
			newArr.push(JSON.parse(key));
		}
	}
	return newArr
}

console.log(removal([123, "meili", "123", "mogu", 123]))  //[123, "meili", "123", "mogu"]
console.log(removal([123, [1, 2, 3], [1, "2", 3], [1, 2, 3], "meili"]))  //[123, [1, 2, 3], [1, "2", 3], "meili"]
console.log(removal([123, {a: 1}, {a: {b: 1}}, {a: "1"}, {a: {b: 1}}, "meili"]))  //[123, {a: 1}, {a: {b: 1}}, {a: "1"}, "meili"]

@ch8839
Copy link

ch8839 commented Jul 25, 2019

先定义一个判断是否相同的函数,类型不同直接返回false,两边为object则递归再次比较

function isOne(left, right) {

  if (typeof left !== typeof right) {
    return false
  }

  if (typeof left == 'object') {
    let isTrue = true
    Object.keys(left).forEach(key => {
      if (typeof left[key] == 'object') {
        isTrue = isOne(left[key], right[key])
      } else {
        if (left[key] !== right[key]) {
          isTrue = false
        }
      }
    });
    return isTrue
  } else {
    if (left === right)
      return true
  }
}

去重主函数:

function deepFliter(array) {
  let result = []

  for (let i = 0; i < array.length; i++) {
    let temp = true
    for (let j = i + 1; j < array.length; j++) {
      if (isOne(array[j], array[i])) {
        temp = false
      }
    }
    if (temp) {
      result.push(array[i])
    }
  }
  return result
}
let array = [123, { a: 1 }, { a: { b: 1 } }, { a: "1" }, { a: { b: 1 } }, "meili"]
console.log(deepFliter(array))

@liangmuren
Copy link

用JSON.stringify的,没考虑object里的key顺序不同?😑做题前要把情况考虑清楚
image

那么key顺序不同的应该输出哪个key顺序的结果呢

@win7killer
Copy link

so, @yygmind 这题需要考虑键顺序不同的 json 么

@wingmeng
Copy link

wingmeng commented Jul 25, 2019

没有什么数组去重是一个 new Set 解决不了的……等一下,你是说数组项里还可能有对象或数组?打扰了……


function removeRepeat(arr) {
  const map = new Map();
  
  // 先用 Set 过滤一波,过滤掉重复的基本类型
  return [...new Set(arr)].filter(item => {
    // 这里现在只剩下引用类型了
    // 把引用类型转为 string,作为 Map 的键名
    const key = JSON.stringify(item);
    
    // 判断是否有此键名
    if (!map.has(key)) {
      map.set(key, true);
      return true;
    }
  });
}

const test = [
  {
    it:     [123, "meili", "123", "mogu", 123],
    expect: [123, "meili", "123", "mogu"]
  }, {
    it:     [123, [1, 2, 3], [1, "2", 3], [1, 2, 3], "meili"],
    expect: [123, [1, 2, 3], [1, "2", 3], "meili"]
  }, {
    it:     [123, {a: 1}, {a: {b: 1}}, {a: "1"}, {a: {b: 1}}, "meili"],
    expect: [123, {a: 1}, {a: {b: 1}}, {a: "1"}, "meili"]
  }
];

test.map(item => {
  const result = removeRepeat(item.it);
  const isPassed = JSON.stringify(result) === JSON.stringify(item.expect);

  console.group(result);
  isPassed ? console.log('%c√ Pass', 'color: green') :
    console.log('%c× Failed', 'color: red');
  console.groupEnd();
});

image

@chejingchi
Copy link

//false 不相等  true相等
function compareArray(t, j) {
	if (t instanceof Array && j instanceof Array && t.length === j.length) {
		let flag = true;
		for (let i = 0; i < t.length; i++) {
			flag = flag && t[i] === j[i];
			if (!flag) {
				break;
			}
		}
		return flag;
	}
}
//false 不相等  true相等
function compareObject(obj1, obj2) {
	let retObj1 = {};
	let retObj2 = {};
	let flag = true;
	transform(obj1, '', retObj1);
	transform(obj2, '', retObj2);
	for (let key in retObj1) {
		if (retObj1[key] !== retObj2[key]) {
			flag = false;
			break;
		}
	}
	return flag;
}
var transform = function (entry, str, temp) {
	for (let key of Object.keys(entry)) {
		if (typeof entry[key] === "object") {
			transform(entry[key], str + key + '.', temp);
		} else {
			str += key;
			temp[str] = entry[key];
		}
	}
}
function test(tmp) {
	return Array.from(new Set(tmp)).reduce((prev, curr) => {
		let flag = false
			for (let t of prev) {
				if (typeof t === 'object') {
					if (curr instanceof Array) {
						flag = !flag && compareArray(t, curr);
						if (flag) {
							break;
						}
					} else if (curr instanceof Object) {
						flag = !flag && compareObject(t, curr)
							if (flag) {
								break;
							}
					}
				}
			}
			if (!flag) {
				prev.push(curr)
			}
			return prev
	}, [])
}

大佬们给看下行不行呢?

@wqvbwang
Copy link

wqvbwang commented Jul 25, 2019

function unique(arr) {
  const result = [];
  const isArray = Array.isArray;
  for (let v of arr) {
    result.every(e => !equal(v, e)) && result.push(v);
  }
  return result;

  function equal(a, b) {
    if (a && b && typeof a === 'object' && typeof b === 'object') {
      return isArray(a) === isArray(b)
        && (isArray(a) ?
            a.length === b.length && a.every((e, i) => equal(e, b[i]))
            : Object.keys(a).length === Object.keys(b).length && Object.keys(a).every(k => equal(a[k], b[k]))
        );
    } else {
      return a === b;
    }
  }
}

@magicds
Copy link

magicds commented Jul 25, 2019

问题

问题实际上是一个去重问题,在 === 的基础上新增如下两条规则:

  • 规则1:如果是数组 则每个元素相等认为两个数组相等
  • 规则2:如果是对象 则每个键的值都相等则认为两个对象相等

去重本身就是遍历数组比较而已,因此重点是实现含有以上两条扩展规则的比较函数。

实现比较函数思路:

  1. 判断函数中首先获取类型,若类型不等,则这两个值不相等,若类型相同,继续比较。
  2. 如果都为数组,遍历数组,比较每个成员,比较方法为当前方法。
  3. 如果都为对象,遍历对象键名,比较对应键值是否相等,比较方法为当前方法。
  4. 其他情况直接使用 === 比较。

去重思路:

  1. 对输入数组使用 reduce 方法遍历,传递初始累计值为 []
  2. reduce 回调函数中对当前累计值使用 some 方法检查当前元素是否存在,不存在则加入即可。
  3. 完成 reduce 遍历后累计值即为去重后的数组。

代码实现

// 辅助函数 用于类型获取
var 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 + '';
        }
        const str = Object.prototype.toString.call(obj);
        return typeof obj === 'object' || typeof obj === 'function' ? class2type[str] || 'object' : typeof obj;
    };
})();

/**
 * 判断两个元素是否相等
 * 在 === 的基础上 有如下扩展规则
 * 规则1:如果是数组 则每个元素相等认为两个数组相等
 * 规则2:如果是对象 则每个键的值都相等则认为两个对象相等
 * @param {any} target 比较元素
 * @param {any} other 其他元素
 * @returns {Boolean} 是否相等
 */
function isEqual(target, other) {
    const t1 = getType(target);
    const t2 = getType(other);

    // 类型不同
    if (t1 !== t2) return false;

    if (t1 === 'array') {
        if (target.length !== other.length) return false; // 数组长度不等
        // 比较当前数组和另一个数组中的每个元素
        return target.every((item, i) => {
            // return item === target;
            return isEqual(item, other[i]);
        });
    }

    if (t2 === 'object') {
        // 对象情况类似数组 但是遍历方法区别一下
        const keysArr = Object.keys(target);
        if (keysArr.length !== Object.keys(other).length) return false;
        return keysArr.every(k => {
            return isEqual(target[k], other[k]);
        });
    }

    return target === other;
}

/**
 * 对输入数组按照指定规则进行去重
 *
 * @param {Array<any>} arr 待去重的数组
 * @returns {Array<any>} 去重后的新数组
 */
function unique(arr) {
    return arr.reduce((outputArr, current) => {
        const isUnique = !outputArr.some(item => isEqual(current, item));
        if (isUnique) {
            outputArr.push(current);
        }
        return outputArr;
    }, []);
}

@YoungYang7
Copy link

YoungYang7 commented Sep 11, 2019

参考了大家的JSON.stringify

function getUnrepeatArr(arr){
    let obj = {}
    return arr.filter((item) => {
        return obj.hasOwnProperty(JSON.stringify(item)) ? false : (obj[JSON.stringify(item)] = true)
    })
}

测试了三个用例,可以输出正确结果。

@fengshenhai-0727
Copy link

/*

第 113 题:编程题,根据以下要求,写一个数组去重函数(蘑菇街)
如传入的数组元素为[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"]

*/
function unique(arr) {
  const res = [];
  const isObject = item =>
    Object.prototype.toString.call(item) === "[object Object]";
  const isArray = item =>
    Object.prototype.toString.call(item) === "[object Array]";
  const compare = (a, b) => {
    if (isArray(a) && isArray(b) && a.length === b.length) {
      for (let i = 0; i < a.length; i++) {
        if (!compare(a[i], b[i])) {
          return false;
        }
      }
      return true;
    } else if (isObject(a) && isObject(b)) {
      if (Object.values(a).length === Object.values(b).length) {
        for (let key in a) {
          if (!compare(a[key], b[key])) {
            return false;
          }
        }
        return true;
      } else {
        return false;
      }
    } else {
      if (a === b) {
        return true;
      }
      return false;
    }
  };

  const find = function(res, item) {
    if(res.length==0){
        return false;
    }
    for (let i = 0; i < res.length; i++) {
      if (compare(res[i], item)) {
        return true;
      }
    }
    return false;
  };
  for (let i = 0; i < arr.length; i++) {
    if (!find(res, arr[i])) {
      res.push(arr[i]);
    }
  }
  return res;
}
console.log(unique([123, "meili", "123", "mogu","123"]));
console.log(unique([123, [1, 2, 3], [1, "2", 3], [1, 2, 3], "meili"]));
console.log(unique([123, {a: 1}, {a: {b: 1}}, {a: "1"}, {a: {b: 1}}, "meili"]));

@aeolusheath
Copy link

          function getArr(arr) {
              let set = new Set()
              let mArr = []
              for(let i = 0; i < arr.length; i++) {
                if (Array.isArray(arr[i]) || typeof (arr[i]) == 'object') {
                  let str = JSON.stringify(arr[i])
                  if (!mArr.includes(str)) {
                    set.add(arr[i])
                    mArr.push(str)
                  }
                } else {
                  set.add(arr[i])
                }
              }
              return [...set]
             }

@JayChen1989
Copy link

JayChen1989 commented Nov 21, 2019

function isObject(value){
    return Object.prototype.toString.call(value) === '[object Object]';
}
function isEqual (t1,t2) {
    let arr = Object.entries(t1);
    let res = true;
    if(arr.length !== Object.keys(t2).length){
        return false
    }
    arr.forEach(item=>{
        let i = item[0];
        let v = item[1];
        if(
            (Array.isArray(v) && Array.isArray(t2[i])) ||
            (isObject(v) && isObject(t2[i]))
        ){
            res = equalArray(v,t2[i])
        }else{
            v !== t2[i] && (res = false)
        }
    })
    return res;
}

function deWeight(arr){
    let res = [];
    for(let i = 0;i<arr.length;i++){
        if(Array.isArray(arr[i]) || isObject(arr[i])){
            res.every(item=>{
                return !isEqual(item,arr[i])
            }) && res.push(arr[i])
        }else{
            res.indexOf(arr[i]) === -1 && res.push(arr[i])
        }
    }
    return res
}

@sisterAn
Copy link
Collaborator

sisterAn commented Nov 27, 2019

function dedup(list = []) {
    let m = new Map()
    Array.from(new Set(list)).map(item => {
        if (typeof(item) === 'object') {
            if (!m.has(JSON.stringify(item))) {
                m.set(JSON.stringify(item), item)
            }
        } else {
            m.set(item, item)
        }
    })
    return [...m.values()]
}
dedup([123, "meili", "123", "mogu", 123])
dedup([123, [1, 2, 3], [1, "2", 3], [1, 2, 3], "meili"])
dedup([123, {a: 1}, {a: {b: 1}}, {a: "1"}, {a: {b: 1}}, "meili"])

数组去重

@maginapp
Copy link

对象转化为数组格式排序后,再用JSON.stringify处理,解决键名顺序问题

const arr1 = [123, "meili", "123", "mogu", 123];
const arr2 = [123, [1, 2, 3], [1, "2", 3], [1, 2, 3], "meili"];
const arr3 = [123, { a: 1 }, { a: { b: 1 } }, { a: "1" }, { a: { b: 1 } }, "meili", { a: { b: 1, c: 2, d: 4 } }, { a: { d: 4, c: 2, b: 1 } }];
const arr4 = [{ b: 1, c: 2 }, { c: 2, b: 1 }];

const cutRepeatNotype = (arr) => {
    const getArray = (data) => {
        if (data instanceof Array) {
            let val = [];
            for (let i = 0; i < data.length; i++) {
                val.push(getArray(data[i]));
            }
            return val;
        }
        else if (data && typeof data === 'object') {
            let val = [];
            let map = new Map();
            for (let k in data) {
                map.set(k, data[k]);
            }
            ([...map.keys()]).sort((a, b) => a > b ? 1 : -1).forEach(k => {
                val.push([k, getArray(map.get(k))]);
            });
            return val;
        }
        else {
            return data;
        }
    };
    let arrStr = arr.map(item => ({
        val: item,
        type: JSON.stringify(getArray(item))
    }));
    let map = new Map();
    return arrStr.filter(item => !map.has(item.type) && map.set(item.type, item.val)).map(item => item.val);
};

console.log(cutRepeatNotype(arr1));
console.log(cutRepeatNotype(arr2));
console.log(cutRepeatNotype(arr3));
console.log(cutRepeatNotype(arr4));

@kylecui2016
Copy link

function delRepeat(originalArr) {
    let arr = originalArr.slice(0)
    for (let i = 0; i < arr.length; i++) {
        for (let j = i + 1; j < arr.length; j++) {
            if (objDeepEqual(arr[i], arr[j])) {
                arr.splice(j, 1)
            }
        }
    }
    return arr
}

function objDeepEqual(source, target) {
    if (typeof source !== typeof target) return false
    if (typeof source === 'object') {
        for (let key in source) {
            if (typeof source[key] !== 'object') {
                if (source[key] !== target[key]) {
                    return false
                }
            } else if (!objDeepEqual(source[key], target[key])) {
                return false
            }
        }
    } else if (source !== target) {
        return false
    }
    return true
}

@yygmind yygmind changed the title 第 113 题:编程题,根据以下要求,写一个数组去重函数 第 113 题:根据以下要求,写一个数组去重函数 Dec 16, 2019
@leslie555
Copy link

leslie555 commented Dec 30, 2019

最笨的方法:

function d(arr) {
  const len = arr.length;
  let myArr = [];
  for (let i = 0; i < len; i++) {
    myArr[i] = JSON.stringify(arr[i])
  }
  let newArr = [];
  for (let i = 0; i < len; i++) {
    if (!newArr.includes(myArr[i])) {
      newArr.push(myArr[i])
    }
  }
  for (let i = 0; i < newArr.length; i++) {
    newArr[i] = JSON.parse(newArr[i])
  }
  return newArr
}

@Linkontoask
Copy link

数组里面还包含引用传递的对象没有管

function equal (source, target) {
    var to = Object.prototype.toString
    var q1 = to.call(source)
    var q2 = to.call(target)
    if (q1 === '[object Array]' && q2 === '[object Array]') {
        return source.every((item, index) => item === target[index])
    } else if (q1 === '[object Object]' && q2 === '[object Object]') {
        for (var k in source) {
            var item = source[k]
            var t = target[k]
            if (to.call(item) === '[object Object]' && to.call(t) === '[object Object]') {
                return equal(item, t)
            }
            if (item !== t) {
                return false
            }
        }
        return true
    } else {
        return source === target
    }
}

function start (a1) {
    
    var result = [].concat(a1), r = []

    while (result.length) {
        var item = result.shift()
        r.push(item)
        for (var i = result.length - 1; i >= 0; i--) {
            if (equal(item, result[i])) {
                result.splice(i, 1)
            }
        }
    }
    
    return r
}

@lovelmh13
Copy link

lovelmh13 commented Jan 29, 2020

写的比较麻烦...

var arr1 = [123, "meili", "123", "mogu", 123];
var arr2 = [123, [1, 2, 3], [1, "2", 3], [1, 2, 3], "meili"];
var arr3 = [123, { a: 1 }, { a: { b: 1 } }, { a: "1" }, { a: { b: 1 } }, "meili"];
var arr4 = [123, { a: 1 }, { a: { b: 1 } }, { a: "1" }, { a: { b: 1 } }, "meili", [1, 2, 3], [1, "2", 3], [1, 2, 3]];

function unique(arr) {
	var arrSet = [... new Set(arr)];
	var arr = [];
	var obj = [];
	arrSet.map((item, index) => {
		type(item, index, arr, obj);
	});
	if (arr.length > 0) {
		for (var i = 0; i < arr.length - 1; i++) {
			for (var j = i + 1; j < arr.length; j++) {	// 通过对应的角标删除arrSet对应的项
				var index1 = arr[i];
				var index2 = arr[j];
				if (JSON.stringify(arrSet[index1]) === JSON.stringify(arrSet[index2])) {
					arrSet.splice(index2, 1);
				}
			}
		}
	}

	if (obj.length > 0) {
		for (var i = 0; i < obj.length - 1; i++) {
			for (var j = i + 1; j < obj.length; j++) {
				var index1 = obj[i];
				var index2 = obj[j];
				if (JSON.stringify(arrSet[index1]) === JSON.stringify(arrSet[index2])) {
					arrSet.splice(index2, 1);
				}
			}
		}
	}
	return arrSet;
}

function type(item, index, arr, obj) {
	if (item instanceof Object) {
		if (Array.isArray(item)) {
			arr.push(index);	// 如果是数组,把对应的角标传入arr
		} else {
			obj.push(index);	// 如果是对象,把对应的角标传入obj
		}
	}
}
console.log(unique(arr4));

@276378532
Copy link

 function diff(arr){
            let res = {};
            let _arr = [];
            for(let i = 0; i < arr.length; i++){
                let key = typeof arr[i] + JSON.stringify(arr[i]);
                if(!res[key]){
                    res[key] = true;
                    _arr.push(arr[i])
                }
            }
            return _arr
        }
        let arr1 = [123, "meili", "123", "mogu", 123];
        let arr2 = [123, [1, 2, 3], [1, "2", 3], [1, 2, 3], "meili"]
        let arr3 = [123, { a: 1 }, { a: { b: 1 } }, { a: "1" }, { a: { b: 1 } }, "meili"]
        console.log(diff(arr1))
        console.log(diff(arr2))
        console.log(diff(arr3))

@ManyDai
Copy link

ManyDai commented Mar 9, 2020

function f(arr){
return [...new Set(arr.map(el=>JSON.stringify(el)))].map(el=>JSON.parse(el))
}

@xwq863728739
Copy link

触及到老夫的知识盲区了

@ihoneys
Copy link

ihoneys commented Jun 28, 2020

const uniq = (arr = []) => arr.reduce((t, c) => (t.includes(c) ? t : t.push(c), t), [])
const uniqArr = [123, "meili", "123", "mogu", 123]
console.log(uniq(uniqArr)) // [[123, "meili", "123", "mogu"]
//下面的不会,哈哈哈哈

@523451928
Copy link

function equals(a, b) {
  if (a === b) return true
  if (a instanceof Date && b instanceof Date) return a.getTime() === b.getTime()
  if (!a || !b || (typeof a !== 'object' && typeof b !== 'object')) return a === b
  if (a.prototype !== b.prototype) return false
  const keys = Object.keys(a)
  if (keys.length !== Object.keys(b).length) return false
  return keys.every(k => equals(a[k], b[k]))
}
function removeRepeat(arr) {
  return arr.reduce((acc, item) => {
    if (!acc.find(a => equals(a, item))) {
      acc.push(item)
    }
    return acc
  }, [])
}
removeRepeat([123, 'meili', '123', 'mogu', 123])

@yjfhtop
Copy link

yjfhtop commented Jul 22, 2020

function getType(data) {
    return Object.prototype.toString.call(data)
}

function ff(arr) {
    let targetArr = Array.from(new Set(arr))
    let obj = {}
    arr.forEach((item, index) => {
        let typeStr = getType(item)
        if (typeStr === '[object Object]' || typeStr === '[object Array]') {
            let valStr = JSON.stringify(item)
            if (obj[valStr]) {
                targetArr.splice(index, 1)
            } else {
                obj[valStr] = true
            }
        }
    })
    return targetArr
}

ff([123, {a: 1}, {a: {b: 1}}, {a: "1"}, {a: {b: 1}}, "meili"])

应该可以... 大概

@yangchaojie456
Copy link

如果 [1,2,3] 和 [1,3,2] 。{a:1,b:2} 和 {b:2,a:1} 也算相等的话

function unique(array) {
    var newArr = [array[0]]
    var len = array.length

    for (var i = 0; i < len; i++) {

        for (var j = 0; j < newArr.length; j++) {
            if (isEq(newArr[j], array[i])) {
                break
            }
            if (j == newArr.length - 1) {
                newArr.push(array[i])
            }
        }
    }

    function isEq(a, b) {
        if (Array.isArray(a) && Array.isArray(b)) {
            var aLen = a.length
            var bLen = b.length
            if (aLen !== bLen) {
                return false
            }
            for (var i = 0; i < aLen; i++) {
                if (!b.includes(a[i])) {
                    return false
                }
            }
            return true
        } else if (typeof a == 'object' && typeof b == 'object') {
            for (const key in a) {
                if (a.hasOwnProperty(key)) {
                    return isEq(a[key], b[key])
                }
            }

        } else {
            return Object.is(a, b)
        }
    }

    return newArr
}

@XuedaoYuan
Copy link

不用搞的这么复杂吧, 上面这么多循环

var arr = [1, -1, 0, 0, 0, 123, [1, 2, 3], [1, '2', 3], [1, 2, 3], 'meili', null, '', null, '', NaN, NaN, undefined, undefined]
// arr = [123, "meili", "123", "mogu", 123]
// arr = [123, {a: 1}, {a: {b: 1}}, {a: "1"}, {a: {b: 1}}, "meili"]
function moveSame(arr) {
	const map = {}
	const result = []
	for (let i = 0, len = arr.length; i < len; i++) {
		const item = arr[i]
		let key
		if (typeof item === 'object') {
			key = JSON.stringify(arr[i])
		} else {
			key = item + typeof item
		}
		if (!map[key]) {
			map[key] = true
			result.push(item)
		}
	}
	return result
}
console.log(moveSame(arr));

@XuedaoYuan
Copy link

用JSON.parse和JSON.stringify的同学,如果数组有undefined是不是就报错了;还有就是如果数组里包含循环引用的对象,是不是就都报错了╮(╯▽╰)╭

考虑的不错, 不过题目显然不是这个意思,而且数组是undefined 也不会报错, 会变成null值,如果非要这么搞, 那么就对数组或者对象的值先做针对处理,再用stringify。
引用对象确实是个应该考虑的事情, 不过这样子联想下去,那问题就太多了。 满足 1 2 3 三个条件,算法复杂度过得去就算吧。毕竟测试用例就这三个

@JaykeyGuo
Copy link

一个for循环搞定

function filter(arr) {
  let map = {};
  let result = [];
  for (let i = 0; i < arr.length; i++) {
    console.log(JSON.stringify(arr[i]))
    if (!map[JSON.stringify(arr[i])]) {
      map[JSON.stringify(arr[i])] = true;
      result.push(arr[i]);
    }
  }
  return result;
}

使用一个对象来保存已有的数据。

@WJiaoJiao
Copy link

var arr = [123, [1, 2, 3], [1, "2", 3], [1, 2, 3], "meili"];

function test(input) {
  var t  = input.reduce(function (acc, item){
    acc[JSON.stringify(item)] = item;
    return acc;
  }, {});
  return Object.keys(t).map(k => t[k])
}

console.log(test(arr))

@XW666
Copy link

XW666 commented Mar 30, 2021

const find10 = () => {
let arr55 = [123, [1, 2, 3], [1, "2", 3], [1, 2, 3], "meili"]
let obj = {}
arr55.forEach(item => {
if (!obj[JSON.stringify(item)]) {
obj[JSON.stringify(item)] = item
}
})
let list = Object.values(obj)

}
find10()

@zhelingwang
Copy link

zhelingwang commented May 11, 2021

function transform(arr) {
  const set = new Set(arr.map(itm => itm !== void 0 ? JSON.stringify(itm) : void 0));
  return Array.from(set).map(itm => {
    if (itm === void 0) return void 0;
    const parsed = JSON.parse(itm);
    return typeof parsed !== 'object' ? JSON.parse(itm) : parsed;
  })
}

console.log(
  transform(
    // [123, "meili", "123", "mogu", 123]
    // [123, [1, 2, 3], [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 } }, undefined, { a: "1" }, { a: { b: 1 } }, "meili", null]
  )
);

@hanatsuka
Copy link

考虑对象的key值顺序,稍微麻烦了点

function deleteMul(arr) {
    let set = new Set(arr);
    arr = Array.from(set);
    const is = (target) => Object.prototype.toString.call(target);
    let objSet = [],
        arrSet = [];
    for (const iterator of arr) {
        switch (is(iterator)) {
            case "[object Object]":
                objSet.push(iterator);
                set.delete(iterator);
                break;
            case "[object Array]":
                arrSet.push(iterator);
                set.delete(iterator);
                break;
            default:
                break;
        }
    }
    const isSameObj = (a, b) => {
        const aKeys = Object.keys(a),
            bKeys = Object.keys(b);
        if (aKeys.length !== bKeys.length) return false;
        aKeys.sort((_a, _b) => _a - _b);
        bKeys.sort((_a, _b) => _a - _b);
        let i = 0;
        while (i < aKeys.length) {
            const aK = aKeys[i],
                bK = bKeys[i];
            if (aK !== bK) {
                return false;
            } else {
                if (a[aK] !== b[bK]) {
                    const aType = is(a[aK]),
                        bType = is(b[bK]);
                    if (aType !== bType) return false;
                    switch (aType) {
                        case "[object Object]":
                            if (!isSameObj(a[aK], b[bK])) return false;
                            break;
                        case "[object Array]":
                            if (!isSameArr((a[aK], b[bK]))) return false;
                            break;
                        default:
                            return false;
                    }
                }
            }
            i++;
        }
        return true;
    };
    const isSameArr = (a, b) => {
        if (a.length !== b.length) return false;
        for (let i = 0; i < a.length; i++) {
            if (a[i] === b[i]) {
                continue;
            } else {
                const aType = is(a),
                    bType = is(b);
                if (aType !== bType) return false;
                switch (aType) {
                    case "[object Object]":
                        if (!isSameObj(a[i], b[i])) return false;
                        break;
                    case "[object Array]":
                        if (!isSameArr((a[i], b[i]))) return false;
                        break;
                    default:
                        return false;
                }
            }
        }
        return true;
    };
    let repeatSet = new Set();
    for (let i = 0; i < objSet.length - 1; i++) {
        if (repeatSet.has(i)) continue;
        for (let j = i + 1; j < objSet.length; j++) {
            if (repeatSet.has(j)) continue;
            if (isSameObj(objSet[i], objSet[j])) {
                repeatSet.add(j);
            }
        }
    }
    Array.from(repeatSet).forEach((i) => (objSet[i] = null));

    repeatSet.clear();
    for (let i = 0; i < arrSet.length - 1; i++) {
        if (repeatSet.has(i)) continue;
        for (let j = i + 1; j < arrSet.length; j++) {
            if (repeatSet.has(j)) continue;
            if (isSameArr(objSet[i], objSet[j])) {
                repeatSet.add(j);
            }
        }
    }
    Array.from(repeatSet).forEach((i) => (arrSet[i] = null));
    return Array.from(set)
        .concat(objSet.filter((i) => i !== null))
        .concat(arrSet.filter((i) => i !== null));
}

@tbapman
Copy link

tbapman commented Sep 14, 2021

如果数组中都是都是基本数据类型,那么可以使用

function solution(arr){
  return Array.from(new Set(arr))
}

现在是数组中的元素可能是引用数据类型,如对象,数组等,为此可以使用Set集合,Set中有的就跳过,没有就插入新数组

function solution(arr){
    const hashSet=new Set();
    const res=[];
    for(const i of arr){
        if(hashSet.has(JSON.stringify(i))){
            continue;
        }
        hashSet.add(JSON.stringify(i));
        res.push(i)
    }
    return res;
}

// let arr=[123, "meili", "123", "mogu", 123];
// let arr=[123, [1, 2, 3], [1, "2", 3], [1, 2, 3], "meili"]
// let arr=[123, {a: 1}, {a: {b: 1}}, {a: "1"}, {a: {b: 1}}, "meili"]
// let arr=[1,'1',{a:1,b:"1"},{b:'1',a:1},{a:1,b:2},[1,2,3],null,undefined,undefined];

console.log(solution(arr))

let arr=[123, {a: 1,b:2},{b:2,a:1} , {a: "1"} , "meili"]对于该示例,如果判定{a:1,b:2}与{b:2,a:1}相等的话,那么上面的方法暂时不能排除,需要对对象类型进一步判断

@yaoocheng
Copy link

就哈哈哈哈

function test(arr) {
    let map = {};
    let res = []
    for (let i = 0; i < arr.length; i++) {
      if (!map[JSON.stringify(arr[i])]) {
          res.push(arr[i]);
          map[JSON.stringify(arr[i])] = arr[i];
      }
    }
    console.log(res);
    }
    test(arr)

@ddaasss
Copy link

ddaasss commented Nov 15, 2021

const oUniq=arr=>arr.reduce((a,c,i,r)=>{if(typeof c ==='object'){!JSON.stringify(a).includes((JSON.stringify(c)))&&a.push(c) }else{!a.includes(c)&&a.push(c)};return a},[])

@Lingdeqing
Copy link

Lingdeqing commented Mar 16, 2022

  1. 先把对象key排序
  2. 再用map去重
function removeDupObj(items) {
    const map = new Map()
    items.forEach(item => {
        const keySortedObj = sortObjKeys(item)
        map.set(JSON.stringify(keySortedObj), item)
    })
    return [...map.values()]
}

function sortObjKeys(obj) {
    if (obj && typeof obj === 'object') {
        // 数组或对象
        const result = {}
        Object.keys(obj).sort().forEach(k => {
            result[k] = sortObjKeys(obj[k])
        })
        return result
    } else {
        return obj
    }
}

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