【问题标题】:Algorithm to search through and delete repeats in array搜索和删除数组中重复的算法
【发布时间】:2013-07-29 20:37:47
【问题描述】:

我有一个数组,其中一些元素是“重复”,我想删除数组中的重复。

所以比如左边的列表(数组)变成右边的数组:

Ingredients:             Ingredients:
Apples                   Apples
Apples                   Oranges
Oranges                  Bananas
Oranges
Oranges
Bananas 

什么是这样做的好算法?

现在这是我的 psuedocode 的样子:

for each element in ingredients (counter j)
     for each element-below-current-element (counter k)
         if ingredients[i] == element-below-current-element[j]
             splice (delete) ingredients[i]

现在的问题是我注意到如果原始列表有 odd 个元素,那么我可能会得到这样的结果:

Ingredients:             Ingredients:
Apples                   Apples
Oranges                  Oranges
Oranges                  Oranges
Oranges                  Bananas
Bananas

除了我可能会得到一种成分的双倍之外,一切都有效。

这是我的实际代码实现,在 javascript 中并带有一些角度元素(例如 $scope),尽管这并不重要。

    for(var j = 0; j < $scope.groceryList.length; j++){
        for(var k = j+1; k < $scope.groceryList.length; k++){ // for each of elements below current element (j)
            if ( $scope.groceryList[j].name == $scope.groceryList[k].name){
                $scope.groceryList.splice(k, 1);
                }
            }
    }

现在让我感到惊讶的是,每当您删除一个数组元素时,数组长度是如何减少的,​​这会导致您的计数器在下一次迭代中向前跳跃一个元素等等......

【问题讨论】:

  • 谢谢大家的回答!我会花一点时间来浏览它们。

标签: javascript arrays algorithm compare array-splice


【解决方案1】:

Underscore.js 是我推荐的用于在 JavaScript 中进行所有数组处理的工具(以及,对于,只是,就像,一切。太棒了。)

它的uniq 方法恰好可以满足您的需求。

var myArray = ["Apples","Oranges","Oranges","Grapes","Apples"];
_.uniq(myArray);
//returns ["Apples","Oranges","Grapes"]

【讨论】:

  • 我喜欢这个。下划线也是我要走的路。
  • 通过 +1 让全世界都知道!
  • 哇。 _.uniq(myArray); 将清理后的数组返回到哪里?它会自动更新 myArray 还是我需要将其提供给某些东西,即myArray = _.uniq(myArray);?下划线只是语法吗?
  • UnderscoreJS 是一个帮助对集合进行操作的库。因此,您需要包含该库,然后您可以通过_ 变量使用它的功能。查看_.uniqunderscorejs.org/#uniq
  • @Gnuey 基本上_.uniq(myArray) 变成["Apples","Oranges","Grapes"] 所以你可以说console.log(_.uniq(myArray))var MyNewArray = _.uniq(myArray) 等等
【解决方案2】:

在这种情况下,您通常不能将for 循环用于您的内部循环。不过while 效果很好:

for(var j = 0; j < $scope.groceryList.length; j++){
    var k = j+1;
    while(k < $scope.groceryList.length){ // each of elements below current element (j)
        if ( $scope.groceryList[j].name == $scope.groceryList[k].name){
            $scope.groceryList.splice(k, 1);
            }
        else {
            ++k;
            }
        }
}

如果你拼接,不要增加k。如果你不这样做,那就去做吧。

(我希望你的缩进是正确的,这不是我习惯的风格。)

【讨论】:

  • 噢噢噢噢。这是一个聪明简单的方法。纯净而甜美。你的缩进很好:) 谢谢!我喜欢这个社区拥有的所有不同的解决方案。
  • @Gnuey: :-) 很高兴有帮助。
【解决方案3】:

我会对其进行排序,然后像这样比较......

var arr = ["Apples","Oranges","Oranges","Grapes","Apples"];
 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]);
  }
 }

alert(results);

【讨论】:

    【解决方案4】:

    此代码是最简单的解决方案,但需要双倍的内存量——对于您示例中的小数据集来说不是问题。

    Array.prototype.filterDuplicates = function () {
        var filtered = [];
        for (var i = 0; i < this.length; i++)
            if (filtered.indexOf(this[i]) == -1)
                filtered.push(this[i]);
        return filtered;
    }
    

    【讨论】:

    • 哦,太好了。不知道 indexOf 的使用。很有用!
    【解决方案5】:

    我最喜欢的方式是使用数组方法来保存代码:

    arr1=[
        "Apples",
        "Apples",
        "Oranges",
        "Oranges",
        "Oranges",
        "Bananas"
    ];
    
    
    var unq= arr1.filter(function unq(a,b,c){return c.indexOf(a)===b;});
    
    alert(unq); // shows "Apples,Oranges,Bananas"
    

    没有变量,没有工件,只有逻辑和结果。

    编辑:更改为仅使用一个重复数组。 如果你想从另一个数组中筛选出一个数组,只需将上面的“c.indexOf”更改为数组的 var 名称。

    我更喜欢拆分 unq 函数,这样我就可以从任何地方调用 .filter(unq) 来获得一个唯一的数组...

    【讨论】:

    • 等等,但我想从 arr1 获取 arr2。实际上,最初我只是想缩短 arr1。似乎此解决方案假定您已经在 arr2 中拥有缩短的列表?
    • @Gnuey:我理解错了,但现在更简单了!
    • 哇,a、b 和 c 是什么?抱歉,我还不熟悉 filter() 函数:(
    • 这些是通过filter方法生成的,结果是a=index值,b=index,c=whole array。
    【解决方案6】:

    线性时间、常数空间算法:

    1. 有 2 个索引(一个快一个慢),都从零开始
    2. 两者都递增,直到前一个元素与当前元素相同
    3. 增加快的,直到找到不同的元素
    4. 将慢速索引处的元素设置为快速索引处的元素
    5. 两者都增加
    6. 增加快速元素,直到它与替换元素不同
    7. 从 4 开始重复,直到快的结束。
    8. 将列表缩短到最短的那一个

    不,我不能给你 JavaScript。

    示例:

    输入:

    Ingredients, Apples, Apples, Oranges, Oranges, Oranges, Bananas
    

    有 2 个索引(一个快一个慢),都从零开始

       fast
       slow
         V
    Ingredients, Apples, Apples, Oranges, Oranges, Oranges, Bananas
    

    两者都递增,直到我们前一个元素与当前元素相同。

                         fast
                         slow
                           V
    Ingredients, Apples, Apples, Oranges, Oranges, Oranges, Bananas
    

    快速增加直到不同。

                         slow     fast
                           V        V
    Ingredients, Apples, Apples, Oranges, Oranges, Oranges, Bananas
    

    将慢速元素设置为快速元素。

                         slow      fast
                           V         V
    Ingredients, Apples, Oranges, Oranges, Oranges, Oranges, Bananas
    

    两者都增加。

                                   slow     fast
                                     V        V
    Ingredients, Apples, Oranges, Oranges, Oranges, Oranges, Bananas
    

    增加快的,直到它与替换元素不同(橙子)

                                   slow                       fast
                                     V                          V
    Ingredients, Apples, Oranges, Oranges, Oranges, Oranges, Bananas
    

    将慢速元素设置为快速元素。

                                   slow                       fast
                                     V                          V
    Ingredients, Apples, Oranges, Bananas, Oranges, Oranges, Bananas
    

    两者都增加。

                                            slow                  fast
                                              V                     V
    Ingredients, Apples, Oranges, Bananas, Oranges, Oranges, Bananas
    

    到了终点。

    将列表缩短到慢。

    Ingredients, Apples, Oranges, Bananas
    

    【讨论】:

    • 啊,真是有趣的算法!在第一个“increment both”之后,您输入了四个“oranges”。你是故意的吗?感谢您添加此内容!
    • 是的,第二个Apples 被上面的Oranges 取代。
    • 仅适用于排序/分组数组。似乎是这样,但没有明确说明。
    【解决方案7】:

    只需使用关联数组进行存在性检查:

    var exists = {}, i;
    for (i = 0; i < arr.length; i += 1) {
        if (exists[arr[i]]) {
            arr.splice(i, 1);
            i--;
        } else {
            exists[arr[i]] = true;
        }
    }
    // arr should now have no dupes
    

    【讨论】:

      【解决方案8】:

      http://jsfiddle.net/XYsUm/

      var ingredients = [
          "Apples",
          "Apples",
          "Oranges",
          "Oranges",
          "Oranges",
          "Bananas"
      ];
      
      var uniqIngredients = {};
      
      for (i in ingredients) {
          uniqIngredients[ingredients[i]] = true;
      }
      
      ingredients = [];
      
      for (i in uniqIngredients) {
          ingredients.push(i);
      }
      

      【讨论】:

        猜你喜欢
        • 2018-06-12
        • 2012-05-07
        • 2021-11-08
        • 2021-02-16
        • 1970-01-01
        • 1970-01-01
        • 2017-06-09
        • 2016-02-15
        • 2014-03-22
        相关资源
        最近更新 更多