【问题标题】:Returning Unique Values from an Array从数组返回唯一值
【发布时间】:2013-08-24 09:58:00
【问题描述】:

如果我有一个像下面这样的数组作为例子:

myArray = [1,4,5,1,5];

如何删除所有重复值(本例中为所有 1 和 5)并仅返回唯一元素(本例中为 4)。

任何帮助将不胜感激。

【问题讨论】:

标签: javascript jquery


【解决方案1】:

我认为

[1,4,5,1,5].filter(function(x, n, self) { 
    return self.indexOf(x) == self.lastIndexOf(x) 
})

使用下划线的可能更有效的基于哈希的版本:

a =[1, 2, 3, 3, 4, 2, 1, 5]
uniqs = _.chain(a).countBy().pairs().filter(function(x) {
    return x[1] == 1
}).pluck(0).value()

或纯javascript:

a = [1, 2, 3, 3, 4, 2, 1, 5]
hash = {}

a.forEach(function(x) {
    hash[x] = (Number(hash[x]) || 0) + 1
});

uniq = Object.keys(hash).filter(function(n) {
    return hash[n] == 1
});

但是请注意,这会将数组值转换为字符串(结果将是 ["4","5"])。

如果您对正在排序的数组感到满意,也可以这样做:

a = [1, 2, 3, 3, 4, 2, 1, 5]

uniq = a.sort().filter(function(x, n, self) {
    return x != self[n - 1] && x != self[n + 1];
});

//[4, 5]

第二种和第三种方法有一个严重的限制,它们只能处理原始值——你不能“唯一化”一个对象数组。第一个函数工作得很好:

x = {x:1}; y = {y:1}; a = [x, y, x, x];
uniq = a.filter(function(x, n, self) { 
    return self.indexOf(x) == self.lastIndexOf(x) 
})
// {"y":1}

对于那些好奇的,性能测试(在不同的浏览器中相当不一致):http://jsperf.com/efficient-unique/2

【讨论】:

    【解决方案2】:

    This works,并且比简单搜索(O(nlog(n)) 而不是 O(n^2))效率更高,但是它确实会修改现有数组。

    var unique = [];
    
    myArray.sort();
    
    for (var i=0, j;i<myArray.length;i = j) {
        for (j=i+1;j<myArray.length && myArray[i] === myArray[j]; j++);
    
        if (j == i + 1) {
            unique.push(myArray[i]);
        }
    }
    
    // use unique
    

    正如在 cmets 中所讨论的,您还可以利用一个对象并实现 O(n) 解决方案,但是这种方法的执行时间在不同平台之间变化很大(有时比上述解决方案慢,而其他时候更快)。

    var unique = [], hash = {}, curr;
    
    for (var i=0;i<myArray.length;i++) {
        curr = myArray[i];
    
        hash[curr] = (Number(hash[curr]) || 0) + 1;
    }
    
    for (var x in hash) {
        if (hash[x] === 1) {
            unique.push(x);
        }
    }
    
    // use unique
    

    【讨论】:

    • 你有证据证明“效率更高”吗?
    • @thg435:这里有一个 jsPerf 可以满足你的好奇心; jsperf.com/efficient-unique。使用这么小的数组并没有那么更有效率,但收益显然会随着n 的增长而增长。
    • @Matt:所以,“效率更高”显然是不正确的。我建议您更新帖子以反映这一点(并跳过大 O 的东西,这也是错误的)。
    • @thg435:您运行的两个测试(假设是您)表明我的算法比简单方法快两倍(1,900,000 vs 900,000ops/sec)。即使在这么小的阵列上,这怎么不是“效率更高”?想解释一下我的大 O 符号是怎么错的?
    • @Matt:Big O 描述了函数的增长方式,而不是它的“快速”程度。在这种特殊情况下,所有这些“高效”和“大 O”的谈话只会让人们感到困惑。对于
    【解决方案3】:

    试试这个:-

    var arr = [1,4,5,1,5];
    var sorted_arr = arr.sort(); 
    var results = [];
    for (var i = 0; i < arr.length - 1; i++) {
        if (sorted_arr[i + 1] !== sorted_arr[i]) {
            results.push(sorted_arr[i]);
        }
    }
    

    【讨论】:

    • 这不是 OP 想要的。
    • 这仍然不能满足 OP 的要求。
    • @Matt:- 明白了。更新了我的答案!!如果这不起作用,请纠正我!
    • 如果下一个元素!== 是当前元素,你可能想要push(),而不是===。如果数组中的元素出现超过 2 次,这也会失败(例如 [1,1,1,2])。
    • 这不是我的反对意见。如果您解决“如果数组中出现超过 2 次元素(例如 [1,1,1,2]),这也将失败。”的问题,我会给你一个赞成票。跨度>
    【解决方案4】:

    您可以尝试使用这个 jquery 函数: http://api.jquery.com/jQuery.unique/

    “$.unique() 函数搜索对象数组,对数组进行排序,并删除所有重复节点。”

    【讨论】:

    • jQuery.unique 用于 DOMNodes,根据文档。 “对 DOM 元素数组进行排序”。
    猜你喜欢
    • 1970-01-01
    • 2020-08-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-12-25
    • 2021-03-03
    • 2015-07-19
    相关资源
    最近更新 更多