【问题标题】:Javascript array sort and uniqueJavascript数组排序和唯一性
【发布时间】:2011-06-17 13:07:08
【问题描述】:

我有一个这样的 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 中完成所有这些任务?

【问题讨论】:

    标签: javascript arrays sorting unique


    【解决方案1】:

    这其实很简单。如果首先对值进行排序,则查找唯一值要容易得多:

    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"]
    

    【讨论】:

    • 使用a*1 - b*1 而不仅仅是a - b 有什么意义?
    • 在 9 次尝试失败后,Randall Munroe 的 StackSort 将我发送到这里,很好的例子:P gkoberger.github.io/stacksort
    • @FiHoran 好像每次都来这里!
    • 尝试了 15 次,但 StackSort 让我来到了这里。
    • 一个 7 岁的 PR 刚刚被合并为 the stacksort site,感谢 Reddit 上的一个帖子。赞成票来了——它会再次炙手可热。 github.com/gkoberger/stacksort/pull/4
    【解决方案2】:

    在您无法提前定义函数的情况下(例如在书签中),这可能就足够了:

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

    【讨论】:

    • myData.sort().filter(function(el,i,a){return i==a.indexOf(el);})
    • myData.sort().filter(function(el,i,a){return !i||el!=a[i-1];})
    • 不区分大小写:myData.sort().filter(function(el,i,a){return !i||el.toLowerCase()!=a[i-1].toLowerCase();})
    • myData.sort().filter((x,i,a)=&gt;x!=a[i-1])(这将删除第一个空值,但效果很好)
    • ES6 语法:arr.sort().filter((el,i,a) =&gt; (i===a.indexOf(el)));
    【解决方案3】:

    您现在只需 一行 行代码即可获得结果。

    使用new Set 将数组缩减为唯一的一组值。 之后应用sort 方法对字符串值进行排序。

    var myData=['237','124','255','124','366','255']
    
    var uniqueAndSorted = [...new Set(myData)].sort() 
    

    更新用于自提问以来 JavaScript 中引入的较新方法。

    【讨论】:

      【解决方案4】:

      这是我使用Array.protoype.reduce() 的(更现代的)方法:

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

      编辑: cmets 中指出的更高性能版本:

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

      【讨论】:

      • 这是一个不错的解决方案!
      • 这是一个不错的选择,但是当数组很大时速度很慢 - O(n^2) 用于减少,因为您为每个元素调用 indexOf,然后 O(n log n) 用于最后排序。排序后,您只需要线性时间即可删除重复项:)
      【解决方案5】:
      function sort_unique(arr) {
          return arr.sort().filter(function(el,i,a) {
              return (i==a.indexOf(el));
          });
      }
      

      【讨论】:

      • filter 也不是 jQuery。那将是$.filter
      【解决方案6】:

      怎么样:

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

      这类似于@loostro 的答案,但不是使用 indexOf 来重复每个元素的数组以验证是否是第一个找到的,它只是检查下一个元素是否与当前元素不同。

      【讨论】:

      • 这应该是公认的答案。简单,优雅,原生,防弹。其他具有 O(n^2)、外部库、额外函数和数组复制的...我错过了什么,为什么这不应该是最佳答案?
      • 此代码不能按预期工作,它不能正确排序单个数字整数,但如果在 sort() 中还添加 function(a,b) { return a - b; 则它工作正常} codepen.io/ivan-topi/pen/BaybgPB
      【解决方案7】:

      尝试使用外部库,例如 underscore

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

      这依赖于_.compose_.uniq_.sortBy_.identity

      看直播example

      它在做什么?

      我们想要一个函数,它接受一个数组,然后返回一个已排序的数组,其中删除了非唯一条目。这个函数需要做两件事,排序和使数组唯一。

      这是一个很好的组合工作,所以我们将唯一的 & 排序功能组合在一起。 _.uniq 只能用一个参数应用于数组,所以它只是传递给_.compose

      _.sortBy 函数需要一个排序条件函数。它需要一个返回值的函数,并且数组将根据该值进行排序。由于我们排序的值是数组中的值,我们可以传递 _.identity 函数。

      我们现在有一个函数(接受一个数组并返回一个唯一数组)和一个函数(接受一个数组并返回一个排序数组,按它们的值排序)的组合。

      我们只需在数组上应用组合,我们就有了唯一排序的数组。

      【讨论】:

        【解决方案8】:

        此函数不会因超过两个重复值而失败:

        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;
        };
        

        【讨论】:

          【解决方案9】:

          这是一个带有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']
          

          【讨论】:

            【解决方案10】:

            以更优雅的方式解决。

            var myData=['237','124','255','124','366','255'];
            
            console.log(Array.from(new Set(myData)).sort((a,b) => a - b));

            我知道这个问题很老了,但也许有人会派上用场

            【讨论】:

            • 这实际上似乎并不可靠,例如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 感谢您的评论,我已经更新了答案
            【解决方案11】:

            一种使用自定义排序功能的方法

            //func has to return 0 in the case in which they are equal
            sort_unique = function(arr,func) {
                    func = func || function (a, b) {
                        return a*1 - b*1;
                    };
                    arr = arr.sort(func);
                    var ret = [arr[0]];
                    for (var i = 1; i < arr.length; i++) {
                        if (func(arr[i-1],arr[i]) != 0) 
                            ret.push(arr[i]);
                        }
                    }
                    return ret;
                }
            

            示例:对象数组的 desc 顺序

            MyArray = sort_unique(MyArray , function(a,b){
                        return  b.iterator_internal*1 - a.iterator_internal*1;
                    });
            

            【讨论】:

              【解决方案12】:

              没有多余的“返回”数组,没有 ECMA5 内置插件(我很确定!)并且易于阅读。

              function removeDuplicates(target_array) {
                  target_array.sort();
                  var i = 0;
              
                  while(i < target_array.length) {
                      if(target_array[i] === target_array[i+1]) {
                          target_array.splice(i+1,1);
                      }
                      else {
                          i += 1;
                      }
                  }
                  return target_array;
              }
              

              【讨论】:

                【解决方案13】:

                我想我会发布这个答案以获得一些多样性。这种清除重复项的技术是我大约一个月前在 Flash 中的一个项目中学到的东西。

                你要做的是创建一个对象,并利用每个数组项用一个键和一个值填充它。由于重复键被丢弃,重复项被删除。

                var nums = [1, 1, 2, 3, 3, 4, 5, 5, 6, 7, 7, 8, 9, 9, 10];
                var newNums = purgeArray(nums);
                
                function purgeArray(ar)
                {
                    var obj = {};
                    var temp = [];
                    for(var i=0;i<ar.length;i++)
                    {
                        obj[ar[i]] = ar[i];
                    }
                    for (var item in obj)
                    {
                        temp.push(obj[item]);
                    }
                    return temp;
                }
                

                已经有 5 个其他答案,所以我认为不需要发布排序功能。

                【讨论】:

                • 我打算做一个排序功能,但我懒惰地把它留了下来,然后在接受答案时放弃了。我会尽快修改。
                • 这个函数可以扩展为对象而不是基元吗?
                【解决方案14】:
                // Another way, that does not rearrange the original Array 
                // and spends a little less time handling duplicates.
                
                function uniqueSort(arr, sortby){
                    var A1= arr.slice();
                    A1= typeof sortby== 'function'? A1.sort(sortby): A1.sort();
                
                    var last= A1.shift(), next, A2= [last];
                    while(A1.length){
                        next= A1.shift();
                        while(next=== last) next= A1.shift();
                        if(next!=undefined){
                            A2[A2.length]= next;
                            last= next;
                        }
                    }
                    return A2;
                }
                var myData= ['237','124','255','124','366','255','100','1000'];
                uniqueSort(myData,function(a,b){return a-b})
                
                // the ordinary sort() returns the same array as the number sort here,
                // but some strings of digits do not sort so nicely numerical.
                

                【讨论】:

                  【解决方案15】:

                  函数 sort() 仅在您的号码具有相同数字时才有效,例如:

                  var myData = ["3","11","1","2"]
                  

                  会回来的;

                  var myData = ["1","11","2","3"]
                  

                  这里改进了 mrmonkington 的功能

                  myData.sort().sort(function(a,b){return a - b;}).filter(function(el,i,a){if(i==a.indexOf(el) & el.length>0)return 1;return 0;})
                  

                  上面的函数也会删除空数组,你可以看看下面的demo

                  http://jsbin.com/ahojip/2/edit
                  

                  【讨论】:

                  • 为什么要排序两次? &amp; el.length &gt; 0 是怎么回事?
                  【解决方案16】:

                  O[N^2] 解决方案不好,特别是当数据已经排序时,不需要做两个嵌套循环来删除重复项。一个循环并与前一个元素进行比较会很好。

                  使用 sort() 的 O[] 的简单解决方案就足够了。我的解决方案是:

                  function sortUnique(arr, compareFunction) {
                    let sorted = arr.sort(compareFunction);
                    let result = sorted.filter(compareFunction
                      ? function(val, i, a) { return (i == 0 || compareFunction(a[i-1], val) != 0); }
                      : function(val, i, a) { return (i == 0 || a[i-1] !== val); }
                    );
                    return result;
                  }
                  

                  顺便说一句,可以做这样的事情来拥有 Array.sortUnique() 方法:

                  Array.prototype.sortUnique = function(compareFunction) {return sortUnique(this, compareFunction); }
                  

                  此外,如果 compare() 函数返回 0(相等的元素),可以修改 sort() 以删除第二个元素,尽管该代码可能会变得混乱(需要在飞行中修改循环边界)。此外,我不会在解释语言中创建自己的 sort() 函数,因为它肯定会降低性能。所以这个添加是为了 ECMA 2019+ 考虑。

                  【讨论】:

                    【解决方案17】:

                    完成这项任务的最快、最简单的方法。

                    const N = Math.pow(8, 8)
                    let data = Array.from({length:  N}, () => Math.floor(Math.random() * N))
                    let newData = {}
                    let len = data.length
                    
                    // the magic
                    while (len--) {
                        newData[data[len]] = true
                    }
                    

                    【讨论】:

                      【解决方案18】:

                      恐怕你不能结合这些功能,即。你必须这样做:-

                      myData.unique().sort();
                      

                      或者,您可以实现一种 sortedset(在其他语言中可用) - 根据您的需要,它包含排序和删除重复项的概念。

                      希望这会有所帮助。

                      参考:-

                      Array.sort

                      Array.unique

                      【讨论】:

                      • 我的 Chrome 不知道这个方法。
                      • 也许您应该指定您建议的 .unique() 不是本机函数,它必须被定义(无论如何在您发布的链接中都有说明)。
                      • 我同意,它会让事情变得更实用,但也许会让事情变得太容易??
                      猜你喜欢
                      • 1970-01-01
                      • 1970-01-01
                      • 2020-09-06
                      • 2013-04-16
                      • 1970-01-01
                      • 1970-01-01
                      • 1970-01-01
                      • 1970-01-01
                      • 2014-07-25
                      相关资源
                      最近更新 更多