数组的去重是个经典问题了,在这里我想首先谈一下underscore的实现方案,然后再谈几个相关的方案

underscore去重

underscore的去重方案其实是最朴素的方案,我们找一个新数组,然后去遍历原数组,如果新数组没有当前被迭代元素就把当前被迭代元素放入新数组。很显然,这个方案的时间复杂度是O(n2)。对于已排序的序列,underscore还做了优化,主要是利用了已排序序列相同元素位置相邻这一特性。

_.uniq = _.unique = function(array, isSorted, iteratee, context) {
    if (!_.isBoolean(isSorted)) {
        context = iteratee;
        iteratee = isSorted;
        isSorted = false;
    }
    if (iteratee != null) iteratee = cb(iteratee, context);
    var result = [];
    var seen = [];
    for (var i = 0, length = getLength(array); i < length; i++) {
        var value = array[i],
        computed = iteratee ? iteratee(value, i, array) : value;
        if (isSorted) {
            // 已排序数组,和前一个元素比较就能知道是否重复
            if (!i || seen !== computed) result.push(value);
            seen = computed;
        } else if (iteratee) {
            // 遍历查找是否有重复元素
            if (!_.contains(seen, computed)) {
                seen.push(computed);
                result.push(value);
            }
        } else if (!_.contains(result, value)) {
            result.push(value);
        }
    }
    return result;
};

利用哈希去重

利用哈希去重并不是一种通用的方案。传统上在javascript中模拟哈希结构需要利用对象(想用ES6提供的Map的请看下面的ES6方案),但是适用对象有个严重的问题是键的类型都会被转换为字符串,像[1,'1'],这样的数组就不能使用哈希结构去重了。这一般要求数组结构比较规整(对于一般的业务逻辑来说符合这个条件似乎没什么难度)。

下面是这个方案对应的一个实现:

function unique(arr,hasher){
    if(!hasher){
        hasher = function(value){
            return value
        }
    }
    var obj = {};
    arr.forEach(function(item){
        var key = hasher(item);
        obj[key] = item;
    })
    var rst = [];
    var keys = Object.keys(obj);
    keys.forEach(function(item){
        rst.push(obj[item]);
    })
    return rst;
}

ES6去重

利用ES6提供的API实现数组去重非常简单:

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

这主要是利用了集合中的元素不重复这一特性。

results matching ""

    No results matching ""