JavaScript数组排序和去重

70

我有一个 JavaScript 数组,就像这样:

var myData=['237','124','255','124','366','255'];

我需要数组元素是唯一且已排序的:

myData[0]='124';
myData[1]='237';
myData[2]='255';
myData[3]='366';

尽管数组的成员看起来像整数,但它们不是整数,因为我已经将每个成员转换为字符串:

var myData[0]=num.toString();
//...and so on.

有没有办法在JavaScript中完成所有这些任务?

19个回答

158

这其实非常简单。如果先对值进行排序,找到唯一值就更容易了:

function sort_unique(arr) {
  if (arr.length === 0) return arr;
  arr = arr.sort(function (a, b) { return a*1 - b*1; });
  var ret = [arr[0]];
  for (var i = 1; i < arr.length; i++) { //Start loop at 1: arr[0] can never be a duplicate
    if (arr[i-1] !== arr[i]) {
      ret.push(arr[i]);
    }
  }
  return ret;
}
console.log(sort_unique(['237','124','255','124','366','255']));
//["124", "237", "255", "366"]

13
为什么要做 a*1 - b*1 而不是直接做 a - b - NullUserException
247
经过9次失败尝试,Randall Munroe的StackSort最终将我带到这里,真是个好例子 :P https://gkoberger.github.io/stacksort/ - Fi Horan
5
似乎每次都会来到这里! - Persixty
49
经过15次尝试,StackSort 终于帮助我到达了这里。 - Michael Morris
6
由于Reddit上的一篇帖子,7岁的公共关系刚刚被合并到stacksort网站中。点赞来了 - 它又要变得炽热了。 - Jamie
显示剩余9条评论

57

现在您只需使用一行代码即可实现该结果。

使用new Set将数组减少到唯一值的集合。 然后使用sort方法对字符串值进行排序。

var myData=['237','124','255','124','366','255']

var uniqueAndSorted = [...new Set(myData)].sort() 

为最初问题提出后 JavaScript 引入的新方法进行了更新。


41

这可能在你无法事先定义函数(比如在书签脚本中)的情况下是合适的:

myData.sort().filter(function(el,i,a){return i===a.indexOf(el)})

10
myData.sort().filter(function(el,i,a){return i==a.indexOf(el);}) - Ishtar
3
myData.sort().filter(function(el,i,a){return !i||el!=a[i-1];}) - Dave Causey
1
不区分大小写:myData.sort().filter(function(el,i,a){return !i||el.toLowerCase()!=a[i-1].toLowerCase();}) - dfmiller
myData.sort().filter((x,i,a)=>x!=a[i-1])(这将移除第一个 null 值,但是除此之外功能良好) - phaux
1
ES6 语法:arr.sort().filter((el,i,a) => (i===a.indexOf(el))); - Holdsworth

21

这是我采用更现代的方式,使用Array.prototype.reduce()

[2, 1, 2, 3].reduce((a, x) => a.includes(x) ? a : [...a, x], []).sort()
// returns [1, 2, 3]

编辑:如评论中所指出的,这是更加高效的版本:

arr.sort().filter((x, i, a) => !i || x != a[i-1])

2
这是一个可以接受的选择,但是当数组很大时会很慢 - 由于每个元素都调用indexOf,所以reduce的时间复杂度为O(n^2),然后在结尾进行排序的时间复杂度为O(n log n)。一旦你对它进行了排序,你只需要线性时间来删除重复项 :) - rjh

17
function sort_unique(arr) {
    return arr.sort().filter(function(el,i,a) {
        return (i==a.indexOf(el));
    });
}

4
filter 并不是 jQuery 的一部分,它是 $.filter - Ry-

9
怎么样:
array.sort().filter(function(elem, index, arr) {
  return index == arr.length - 1 || arr[index + 1] != elem
})

这与@loostro的答案类似,但是它不使用indexOf来为每个元素重新迭代以验证是否为第一个找到的元素,而是仅检查下一个元素是否与当前元素不同。


这应该是被接受的答案。简单、优雅、本地化、防弹。其他的答案需要 *O(n^2)*、外部库、额外的函数和数组复制... 我错过了什么,为什么这不是最好的答案? - kub1x
1
这段代码不能按预期工作,它无法正确排序单个数字整数,但如果在sort()内部也添加function(a,b) { return a - b; },则可以正常工作。https://codepen.io/ivan-topi/pen/BaybgPB - Ivan Topić

5

尝试使用类似underscore这样的外部库。

var f = _.compose(_.uniq, function(array) {
    return _.sortBy(array, _.identity);
});

var sortedUnique = f(array);

这需要依赖于 _.compose_.uniq_.sortBy_.identity
查看实时 示例它是做什么的? 我们想要一个函数,它接受一个数组并返回一个已排序的数组,其中删除了非唯一条目。这个函数需要做两件事,排序和使数组唯一。
这是组合的好工作,所以我们将唯一和排序函数组合在一起。可以使用一个参数在数组上直接应用 _.uniq,因此它只传递给 _.compose
_.sortBy 函数需要一个排序条件函数。它期望一个返回值的函数,数组将按该值排序。由于我们正在按数组中的值进行排序,因此可以直接传递 _.identity 函数。
现在,我们有了一个函数的组合(接受一个数组并返回一个唯一的数组)和一个函数的组合(接受一个数组并返回一个已排序的数组,按其值排序)。
我们只需将组合应用于数组,就可以得到唯一排序的数组。

5

此函数在出现两个或两个以上重复值时不会失败:

function unique(arr) {
    var a = [];
    var l = arr.length;
    for(var i=0; i<l; i++) {
        for(var j=i+1; j<l; j++) {
            // If a[i] is found later in the array
            if (arr[i] === arr[j])
              j = ++i;
        }
        a.push(arr[i]);
    }
    return a;
};

4

这是一个简单的一行代码,时间复杂度为O(N),不需要复杂的循环。

> Object.keys(['a', 'b', 'a'].reduce((l, r) => l[r] = l, {})).sort()
[ 'a', 'b' ]

解释

原始数据集,假设其来自外部函数

const data = ['a', 'b', 'a']

我们希望以去重的方法将所有值分组为键,并使用对象作为默认值进行reduce操作:
[].reduce(fn, {})

下一步是创建一个reduce函数,将数组中的值放入对象中。最终结果是一个具有唯一键集合的对象。
const reduced = data.reduce((l, r) => l[r] = l, {})

我们设置 l[r] = l 是因为在JavaScript中,当赋值语句用作表达式时,赋值表达式的值将被返回。 l 是累加器对象,r 是键值。如果您需要每个值的计数,则还可以使用 Object.assign(l,{[r]:(l [r] || 0)+1}) 或类似方法来获取每个值的计数。

接下来,我们想要获取该对象的键。

const keys = Object.keys(reduced)

然后只需使用内置排序功能。
console.log(keys.sort())

原始数组的唯一值集合,按照排序顺序。
['a', 'b']

3
一种更优雅的解决方案。

var myData=['237','124','255','124','366','255'];

console.log(Array.from(new Set(myData)).sort((a,b) => a - b));

我知道这个问题很旧,但也许对某些人仍有用。


2
这似乎并不可靠,例如 Array.from(new Set([2,2,3,2,3,4,5,6,7,8,5,6,7,8,9,5,6,7,8,9,10,5,6,7,8,9,10,11,5,6,7,8,9,10,11,12])).sort() 返回 [10,11,12,2,3,4,5,6,7,8,9] - kontur

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接