前端面试:你以为这只是一个简单的数组去重吗?

537次阅读  |  发布于8月以前

前言

之前面试过程被问到数组去重有哪些方式?心想这个问题我会,随便也能说出好几种,也不带多思考的。巴拉巴拉巴拉巴拉。说完,面试官好像不太满意的样子,还问了句,没了吗。我想,咋滴,就这些还不不够用吗。然后就下一题了。

后来我看到这样的数据,忽然意识到,之前的面试怕不是草率了,完全没考虑复杂数据结构,难怪他听完不太满意的样子。

let arr = [1, 1, '2', 3, 1, 2,
    { name: '张三', id: { n: 1 }},
    { name: '张三', id: { n: 1 }},
    { name: '张三', id: { n: 2 }}
]

在平时的开发过程中这样的数据应该少见,绝大部分的数组中数据格式应该保持一致,特殊情况就不管他了。

今天再来出一期数组去重的方式。

基本数据类型去重

确实有多种方式,比如set结构转一下,lodash提供的uniq方法,或者自己利用其他方式实现也是很多的。今天就介绍几个

当面试官询问数组去重时,可以考虑到数组可能包含基本数据类型、引用数据类型,或者混合了两种类型的情况。以下是针对不同情况的多种思路和实现方法:

使用 Set 数据结构(ES6)

const array = [1, 2, 3, 3, 4, 5, 5];
const uniqueArray = [...new Set(array)];
console.log(uniqueArray); // [1, 2, 3, 4, 5]

使用 Array.prototype.filter()

const array = [1, 2, 3, 3, 4, 5, 5];
const uniqueArray = array.filter((item, index) => array.indexOf(item) === index);
console.log(uniqueArray); // [1, 2, 3, 4, 5]

使用 Array.prototype.reduce()

const array = [1, 2, 3, 3, 4, 5, 5];
const uniqueArray = array.reduce((acc, curr) => {
    if (!acc.includes(curr)) {
        acc.push(curr);
    }
    return acc;
}, []);
console.log(uniqueArray); // [1, 2, 3, 4, 5]

使用 for 循环和 Array.prototype.indexOf()

const array = [1, 2, 3, 3, 4, 5, 5];
const uniqueArray = [];
for (let i = 0; i < array.length; i++) {
    if (uniqueArray.indexOf(array[i]) === -1) {
        uniqueArray.push(array[i]);
    }
}
console.log(uniqueArray); // [1, 2, 3, 4, 5]

Lodash 是一个非常流行的 JavaScript 工具库,提供了许多实用的函数来简化开发过程。它也包含了一些用于数组去重的方法。以下是几种利用 Lodash 实现数组去重的方法:

使用 _.uniq() 方法

const _ = require('lodash');

const array = [1, 2, 3, 3, 4, 5, 5];
const uniqueArray = _.uniq(array);
console.log(uniqueArray); // [1, 2, 3, 4, 5]

使用 _.uniqWith() 方法(使用自定义比较函数)

const _ = require('lodash');

const array = [{id: 1}, {id: 2}, {id: 1}];
const uniqueArray = _.uniqWith(array, (a, b) => _.isEqual(a, b));
console.log(uniqueArray); // [{id: 1}, {id: 2}]

2. 数组包含引用数据类型:

使用 Set 数据结构,利用自定义比较函数(如果需要去重对象数组)

const array = [{id: 1}, {id: 2}, {id: 1}];
const uniqueArray = Array.from(new Set(array.map(JSON.stringify)), JSON.parse);
console.log(uniqueArray); // [{id: 1}, {id: 2}]

使用 Array.prototype.reduce()

const array = [{id: 1}, {id: 2}, {id: 1}];
const uniqueArray = array.reduce((acc, current) => {
    const isExist = acc.some(item => JSON.stringify(item) === JSON.stringify(current));
    if (!isExist) acc.push(current);
    return acc;
}, []);
console.log(uniqueArray); // [{id: 1}, {id: 2}]

上面都是使用了JSON.stringfy。但有个问题,如果引用数据的顺序不一样,转的string就不等了。所以还是自己实现一个方法好一些。

使用自定义比较函数

这种方法适用于任何类型的数组,包括混合了基本数据类型和引用数据类型的数组。

function uniqueArray(array) {
    const seen = new Map();
    return array.filter(item => {
        if (typeof item === 'object' && item !== null) {
            const key = Object.keys(item).sort().map(k => `${k}:${item[k]}`).join('|');
            if (!seen.has(key)) {
                seen.set(key, true);
                return true;
            }
        } else {
            if (!seen.has(item)) {
                seen.set(item, true);
                return true;
            }
        }
        return false;
    });
}

const array = [1, 2, {id: 1}, {id: 2}, 1, {id: 1}];
const uniqueArr = uniqueArray(array);
console.log(uniqueArr); // [1, 2, {id: 1}, {id: 2}]

这个方法利用了 Map 数据结构的特性,用键来存储数组中的元素,保证了元素的唯一性。对于对象,通过将属性名排序并拼接成字符串来判断是否重复。

如果都是引用结构,我们平时也可以使用 _.uniqBy() 方法去重,比如根据id什么的

const _ = require('lodash');

const array = [{id: 1}, {id: 2}, {id: 1}];
const uniqueArray = _.uniqBy(array, JSON.stringify);
console.log(uniqueArray); // [{id: 1}, {id: 2}]

总结

在回答问题前先思考题干,尽可能考虑全面,只根据一个方向解读结果始终是不完整的,最后感慨一下,感觉今年没有金三银四,找工作真的卷。

Copyright© 2013-2020

All Rights Reserved 京ICP备2023019179号-8