【问题标题】:Javascript algorithm to find elements in array that are not in another arrayJavascript算法在数组中查找不在另一个数组中的元素
【发布时间】:2011-02-27 03:25:41
【问题描述】:

我正在寻找一种好的算法来获取一个数组中不是另一个数组中的元素的所有元素。所以给定这些数组:

var x = ["a","b","c","t"];
var ​​​​​​​​​y = [​​​​​​​"d","a","t","e","g"];

我想得到这个数组:

var z = ["d","e","g"];

我正在使用 jquery,所以我可以利用 $.each()$.inArray()。这是我想出的解决方案,但似乎应该有更好的方法。

// goal is to get rid of values in y if they exist in x
var x = ["a","b","c","t"];
var y = ["d","a","t","e","g"];

var z = [];
$.each(y, function(idx, value){
  if ($.inArray(value,x) == -1) {
    z.push(value);
  }
});
​alert(z);  // should be ["d","e","g"]

这里是code in action。有什么想法吗?

【问题讨论】:

    标签: javascript jquery algorithm arrays


    【解决方案1】:

    我现在已经很晚了,但也许它会对某人有所帮助。

    如果数组不仅仅是一个简单的数组,而是一个对象数组,那么可以使用以下内容:

    var arr1 = [
        {
          "prop1": "value1",
          "prop2": "value2",
        },
        {
          "prop1": "value3",
          "prop2": "value4",
        },
        {
          "prop1": "value5",
          "prop2": "value6",
        },
      ];
    
    var arr2 = ['value1','value3', 'newValue'];
    
    // finds all the elements of arr2 that are not in arr1
    arr2.filter( 
        val => !arr1.find( arr1Obj => arr1Obj.prop1 === val)
    ); // outputs "newValue"
    
    

    【讨论】:

      【解决方案2】:

      在 ES6 中

      const a1 = ["a", "b", "c", "t"];
      const a2 = ["d", "a", "t", "e", "g"];
      
      console.log( a2.filter(x => !a1.includes(x)) );

      (另一个选项是a2.filter(x => a1.indexOf(x)===-1)

      【讨论】:

        【解决方案3】:
         findDiff = (A, B) => {
             return  A.filter(function (a) {
                  return !B.includes(a);
             });
         }
        

        【讨论】:

        • 虽然此代码可能会回答问题,但提供有关此代码为何和/或如何回答问题的额外上下文可提高其长期价值。我建议您查看 SO 的 official How to Answer article 以及来自 Jon Skeet 的综合 blog post
        【解决方案4】:

        使用新的 ECMA5 javascript 延迟回答:

        var x = ["a","b","c","t"];
        var y = ["d","a","t","e","g"];
        
        myArray = y.filter( function( el ) {
          return x.indexOf( el ) < 0;
        });
        

        【讨论】:

        • 对算法复杂性/可扩展性有任何想法吗?
        • @mikecsh 可能不好。先排序然后再通过可能会更好。
        • @ccook 证明你的陈述实际上可能有用。否则只是一个“可能......也许”的句子。
        【解决方案5】:

        这是一个较晚的答案,但它不使用任何库,因此有些人可能会觉得它很有帮助。

        /**
         * Returns a non-destructive Array of elements that are not found in
         * any of the parameter arrays.
         *
         * @param {...Array} var_args   Arrays to compare.
         */
        Array.prototype.uniqueFrom = function() {
          if (!arguments.length)
            return [];
          var a1 = this.slice(0); // Start with a copy
        
          for (var n=0; n < arguments.length; n++) {
            var a2 = arguments[n];
            if (!(a2 instanceof Array))
              throw new TypeError( 'argument ['+n+'] must be Array' );
        
            for(var i=0; i<a2.length; i++) {
              var index = a1.indexOf(a2[i]);
              if (index > -1) {
                a1.splice(index, 1);
              } 
            }
          }
          return a1;
        }
        

        例子:

        var sheetUsers = ['joe@example.com','fred@example.com','sam@example.com'];
        var siteViewers = ['joe@example.com','fred@example.com','lucy@example.com'];
        var viewersToAdd = sheetUsers.uniqueFrom(siteViewers);  // [sam@example.com]
        var viewersToRemove = siteViewers.uniqueFrom(sheetUsers);  // [lucy@example.com]
        

        【讨论】:

          【解决方案6】:

          这是使用underscore.js 的替代方法:

          function inAButNotInB(A, B) {
            return _.filter(A, function (a) {
              return !_.contains(B, a);
            });
          }
          

          【讨论】:

          • 我已经摆脱了对 jquery 的依赖,并且正在使用较小的库,例如下划线和 lodash。这些库使解决原始问题之类的问题变得更加容易。感谢您提供基于下划线的解决方案!
          【解决方案7】:

          首先制作数组的排序副本。如果顶部元素相等,则将它们都删除。否则删除较少的元素并将其添加到结果数组中。如果一个数组为空,则将另一个数组的其余部分添加到结果中并完成。您可以遍历排序的数组而不是删除元素。

          // assume x and y are sorted
          xi = 0; yi = 0; xc = x.length; yc = y.length;
          while ( xi < xc && yi < yc ) {
            if ( x[xi] == y[yi] ) {
              xi += 1;
              yi += 1;
            } else if ( x[xi] < y[yi] ) {
              z.push( x[xi] );
              xi += 1;
            } else {
              z.push( y[yi] );
              yi += 1;
            }
          }
          // add remainder of x and y to z.  one or both will be empty.
          

          【讨论】:

          • @Drawnonward:感谢您的建议。我了解您在做什么,但我想将我的代码压缩为尽可能简单和轻量级的东西,希望利用现有的 jquery 代码。如果我遇到性能问题,我会考虑你的想法。
          • 好并不总是意味着快,但我是这样理解的。享受吧。
          【解决方案8】:

          Maybe jLinq can help you?

          它允许您对 javascript 对象运行这样的查询。

          例如:

          var users = [ { name: "jacob", age: 25 },  { name: "bob" , age: 30 }]
          var additionalusers = [ { name: "jacob", age: 25 },  { name: "bill" , age: 25 }]
          
          var newusers = jLinq.from(users).except(additionalusers).select();
          
          >>> newusers = [ { name: "bob" , age: 30 } ]
          

          目前这对你来说有点矫枉过正,但我​​很高兴了解到这是一个强大的解决方案。

          它可以做相交、联合、处理布尔逻辑和各种伟大的 linq 风格。

          【讨论】:

          • 很棒的图书馆,还没见过。对于我的即时需求来说可能还是有点多,但我可能会为我需要做的其他一些事情试一试。谢谢!
          【解决方案9】:
          var z = $.grep(y, function(el){return $.inArray(el, x) == -1}); 
          

          另外,该方法名称太短了,不适合它自己。我希望它的意思是 isElementInArray,而不是 indexOf。

          有关对象的演示,请参阅http://jsfiddle.net/xBDz3/6/

          【讨论】:

          • 嗯,我的情况在我的数组中有对象,而不仅仅是简单的字符串。我在我的问题中加入了字符串以简化事情。我不确定您的解决方案是否有效。
          • 名称 grep 可能具有误导性。它实际上与字符串没有任何关系。它只需要一个谓词。其他语言称为相同的事物过滤器。我做了一个demo
          • 哇,经过快速测试,看起来确实有效。命令 grep 具有误导性,因为我假设它可以处理像 unix 命令这样的文本。我会再做一些测试。
          • 注意当前对小提琴代码的支持:JSON.stringify(z) 适用于 Chrome 55,其中 z.toSource() 出错。
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2016-09-24
          • 1970-01-01
          相关资源
          最近更新 更多