JS 数组完全去重

139 阅读1分钟

Source code

function filterRepeat(sourceData) {
	if (!sourceData || Object.prototype.toString.call(sourceData) !== '[object Array]')
		throw new Error('参数 sourceData 必须是一个数组');
	else if (sourceData.length === 0) return sourceData;

	let entriesData = [];
	let repeatIndexes = [];

	entriesData = generatorEntriesData(sourceData);
	repeatIndexes = getRepeatIndexes(entriesData);

	console.log('----- 重复项的 index -----');
	console.log(repeatIndexes, '\n');

	return filter(sourceData, repeatIndexes);
}

function generatorEntriesData(sourceData) {
	let sourceCacheData = [];
	let dataType = '';
	let result = null;

	for (let data of sourceData) {
		dataType = Object.prototype.toString.call(data);

		if (dataType === '[object Array]') {
			result = generatorEntriesData(data);
		} else if (dataType === '[object Object]') {
			result = generatorEntriesData(Object.entries(data));
		} else if (dataType === '[object Function]') {
			result = data.toLocaleString();
		} else {
			result = data;
		}

		sourceCacheData.push(result);
	}

	return sourceCacheData;
}

function getRepeatIndexes(entries) {
	let indexes = new Set();
	let indexesLen = 0;
	let arrIndexes = []; // 记录 entries 中是数组的项的 index
	let entriesCache = new Set();
	let isEquals = true;

	for (let i = 0; i < entries.length; i++) {
		if (Object.prototype.toString.call(entries[i]) === '[object Array]') {
			indexesLen = indexes.size;

			for (let index of arrIndexes) {
				isEquals = isEqualsFn(entries[index], entries[i]);

				if (isEquals) {
					indexes.add(i);
					break;
				} else {
					isEquals = true;
				}
			}

			if (indexes.size === indexesLen) {
				arrIndexes.push(i);
			}
		} else if (entriesCache.has(entries[i])) {
			indexes.add(i);
		} else {
			entriesCache.add(entries[i]);
		}
	}

	return indexes;
}

function isEqualsFn(p1, p2) {
	const p1Type = Object.prototype.toString.call(p1);
	const p2Type = Object.prototype.toString.call(p2);
	let isEquals = true;

	if (p1Type === p2Type) {
		if (p1Type === '[object Array]') {
			if (p1.length === p2.length) {
				for (let i = 0; i < p1.length; i++) {
					isEquals = isEqualsFn(p1[i], p2[i]);
					if (!isEquals) break;
				}
			} else {
				 isEquals = false;
			}
		} else if (p1Type === '[object Object]') {
			isEquals = isEqualsFn(Object.entries(p1).sort(), Object.entries(p2).sort());
		} else if (p1Type === '[object Function]') {
			isEquals = p1Type.name === p2Type.name &&
				p1Type.toLocaleString().length === p2Type.toLocaleString().length;
		} else {
			isEquals = p1 === p2;
		}
	} else {
		isEquals = false;
	}

	return isEquals;
}

function filter(sourceData, repeatIndexes) {
	let result = [];

	sourceData.forEach((item, index) => {
		if (!repeatIndexes.has(index)) result.push(item);
	});

	return result;
}

/***** rua~ *****/
let sourceData = [
	1,
	1,
	'2',
	'2',
	null,
	null,
	undefined,
	undefined,
	[1, 2],
	[1, 2],
	[{ id: 1 }, { id: 2 }],
	[{ id: 1 }, { id: 2 }],
	{
		id: 1,
		name: 'Tom'
	},
	{
		id: 1,
		sayHello() {}
	},
	{
		id: 1,
		sayHello() {}
	},
	{
		id: 1,
		sayHello() { return 'Hello'; }
	},
	{
		id: 1,
		sayHello() { return 'Hello'; }
	},
	{
		id: 2,
		sayHello() { return 'Hello'; }
	}
];

console.log('----- 去重之前 -----');
console.log(sourceData, '\n');

const filteredData = filterRepeat(sourceData);

console.log('----- 去重之后 -----');
console.log(filteredData);

Test case

Result