【问题标题】:Javascript array contains/includes sub arrayJavascript 数组包含/包含子数组
【发布时间】:2016-03-13 03:12:41
【问题描述】:

我需要检查一个数组是否包含另一个数组。子数组的顺序很重要,但实际偏移量并不重要。它看起来像这样:

var master = [12, 44, 22, 66, 222, 777, 22, 22, 22, 6, 77, 3]; 

var sub = [777, 22, 22]; 

所以我想知道master 是否包含sub 类似的东西:

if(master.arrayContains(sub) > -1){
    //Do awesome stuff
}

那么如何以优雅/高效的方式完成呢?

【问题讨论】:

  • 在以优雅的方式执行之前 - 先以某种方式实现它。有什么想法吗?
  • 在 JS 中没有优雅的方法来解决您的问题。你最好看看Underscore之类的JS库
  • “你必须看看图书馆”——这太悲观了,真的。
  • 您是否希望以正确的顺序在主阵列中找到 777 ... 22... 222?
  • @NinaScholz 是的,顺序很重要

标签: javascript arrays include contains indexof


【解决方案1】:
var master = [12, 44, 22, 66, 222, 777, 22, 22, 22, 6, 77, 3]; 

var sub = [777, 22, 22]; 

console.log(master.join(',').includes(sub.join(',')))

//true

你可以通过简单的console.log(master.join(',').includes(sub.join(',')))这行代码使用include方法来做到这一点

【讨论】:

    【解决方案2】:

    尝试使用 everyindexOf

    var mainArr = [1, 2, 3, 4, 5]
    var subArr = [1, 2, 3]
    
    function isSubArray(main, sub) {
        return sub.every((eachEle) => {
            return (main.indexOf(eachEle) + 1);
        });
    }
    isSubArray(mainArr, subArr);
    

    【讨论】:

    • 如果您不搜索子数组的确切顺序,这是一个不错的选择。 OP提到The order of the subarray is important,但在你的情况下[1,2,4]也返回true
    【解决方案3】:

    如果在下面运行这个 sn-p 它应该可以工作

    x = [34, 2, 4];
    y = [2, 4];
    y.reduce((included, num) => included && x.includes(num), true);
    

    编辑: @AlexanderGromnitsky 你是对的,这段代码不正确,谢谢你的发现!上面的代码实际上并没有按照操作的要求做。我没有仔细阅读这个问题,这段代码忽略了顺序。一年后,这是我想出的,希望这可以帮助某人。

    var master = [12, 44, 22, 66, 222, 777, 22, 22, 22, 6, 77, 3]; 
    var sub = [777, 22, 22]; 
    var is_ordered_subset = master.join('|').includes(sub.join('|'))
    

    这段代码有点优雅,可以满足 op 的要求。分隔符无关紧要,只要它不是 int 即可。

    【讨论】:

    • 不起作用:它应该为y==[4,2]返回false
    【解决方案4】:

    对于这个答案,我保留了子数组的顺序。意思是,子数组的元素应该是连续的。如果与master比较时有任何多余的元素,则为false。

    我分三步做:

    1. master中找到sub的第一个元素的索引,并将其存储为数组matched_index[]
    2. 对于matched_index[] 中的每个条目,从s_index 开始检查sub 的每个元素是否与master 相同。如果不匹配,则返回 false 并打破 sub 的 for 循环并为 matched_index[] 中的下一个元素开始下一个 for 循环
    3. 在任何时候,如果在master 中找到相同的sub 数组,则循环将中断并返回true。

    function hasSubArray(master,sub){
    
        //collect all master indexes matching first element of sub-array
        let matched_index = [] 
        let start_index = master.indexOf(master.find(e=>e==sub[0]))
        
        while(master.indexOf(sub[0], start_index)>0){
            matched_index.push(start_index)
            let index = master.indexOf(sub[0], start_index)
            start_index = index+1
        } 
    
        let has_array //flag
        
        for(let [i,s_index] of matched_index.entries()){
            for(let [j,element] of sub.entries()){
                if(element != master[j+s_index]) {
                    has_array = false
                    break
                }else has_array = true
            }
            if (has_array) break
        }
        return has_array
    }
    
    var master = [12, 44, 22, 66, 222, 777, 22, 22, 22, 6, 77, 3];
    
    console.log(hasSubArray(master, [777, 22, 22]));
    console.log(hasSubArray(master, [777, 22, 3]));
    console.log(hasSubArray(master, [777, 777, 777]));
    console.log(hasSubArray(master, [44]));
    console.log(hasSubArray(master, [22, 66]));

    【讨论】:

      【解决方案5】:

      我遇到了类似的问题并使用集合解决了它。

      function _hasSubArray( mainArray, subArray )
      {
          mainArray = new Set( mainArray );
          subArray = new Set( subArray );
      
          for ( var element of subArray )
          {
              if ( !mainArray.has( element ) )
              {
                  return false;
              }
          }
          return true;
      }
      

      【讨论】:

      • _hasSubArray([23,34,45,56], [23,34,23]) // returns true, though should return false
      【解决方案6】:

      fromIndex参数的帮助下

      此解决方案的特点是对索引进行封闭,以便在数组中搜索元素的起始位置。如果找到子数组的元素,则搜索下一个元素以递增的索引开始。

      function hasSubArray(master, sub) {
          return sub.every((i => v => i = master.indexOf(v, i) + 1)(0));
      }
      
      var array = [12, 44, 22, 66, 222, 777, 22, 22, 22, 6, 77, 3];
      
      console.log(hasSubArray(array, [777, 22, 22]));
      console.log(hasSubArray(array, [777, 22, 3]));
      console.log(hasSubArray(array, [777, 777, 777]));
      console.log(hasSubArray(array, [42]));

      【讨论】:

      • sub=[777, 22, 3] 返回真。这是故意的吗? OP 确实说过“实际抵消它并不重要”,但我不太确定这意味着什么。
      • 我在问你的代码是否有意匹配,因为只要看看你的例子,我就预计 [777,22,22] 在主数组中必须是连续的,但事实并非如此。跨度>
      • 您实际上还有另一个问题。它应该index = i + 1 以防止对同一字符进行双重匹配。否则[777, 777, 777] 也匹配!
      • @mpen, ad1 ([777, 22, 3]):是的,这是故意的,因为22 的索引比7773 的索引更大,而22 的索引更大。 ad2 ([777, 22, 22]):即true。 ad3 ([777, 777, 777]):你是对的,找到的索引必须增加。
      【解决方案7】:

      只是想出了一个快速的想法,但效率取决于数组的大小

      var master = [12, 44, 22, 66, 222, 777, 22, 22, 22, 6, 77, 3];
      var sub = [777, 22, 22];
      
      if ((master.toString()).indexOf(sub.toString()) > -1 ){
          //body here
      }
      

      【讨论】:

      • 这实际上是我在实现中采用的解决方案,我喜欢它,因为它易于理解。但我觉得它实际上并没有解决问题,原因有两个:它可以在数组上使用原型,我应该得到数组中的实际索引(而不是字符串)。谢谢!
      • 如果var master = [12, 44, 22, 66, 222, 777, 22, 224, 22, 6, 77, 3]; var sub = [777, 22, 22]; 怎么办?这将是非常危险的。
      • @deblocker 它可能类似于someArray.map(value => value.toString()).join(";") 这样字符串将被分隔,避免错误匹配。
      【解决方案8】:

      您可以像这样尝试使用 filterindexOf

      注意:如果我们不涵盖子数组中的顺序,此代码有效。

      Array.prototype.arrayContains = function (sub) {
        var self = this;
        var result = sub.filter(function(item) {
          return self.indexOf(item) > -1;
        });
        return sub.length === result.length;
      }
      

      例如here

      更新:返回master内部子数组的索引(子数组中的覆盖顺序)

      Array.prototype.arrayContains = function(sub) {
        var first;
        var prev;
        for (var i = 0; i < sub.length; i++) {
          var current = this.indexOf(sub[i]);
          if (current > -1) {
            if (i === 0) {
              first = prev = current;
              continue;
            } else {
              if (++prev === current) {
                continue;
              } else {
                return -1;
              }
            }
          } else {
            return -1;
          }
        }
        return first;
      }
      

      演示:here

      【讨论】:

      • 我喜欢你使用原型并且它很简单。如果你能让它返回数组 indexOf 我愿意接受作为答案。
      【解决方案9】:

      编辑

      最初被误解的问题。

      function arrayContainsSub(arr, sub) {
              var first = sub[0],
                  i = 0,
                  starts = [];
      
              while (arr.indexOf(first, i) >= 0) {
                  starts.push(arr.indexOf(first, i));
                  i = arr.indexOf(first, i) + 1;
              }
      
              return !!starts
                          .map(function(start) {
                              for (var i = start, j = 0; j < sub.length; i++, j++) {
                                  if (arr[i] !== sub[j]) {
                                      return false;
                                  }
                                  if (j === sub.length - 1 && arr[i] === sub[j]) {
                                      return true;
                                  }
                              };
      
                          }).filter(function(res) {
                              return res;
                          }).length;
          }
      

      此解决方案将递归检查所有可用的起点,因此子的第一个索引在数组中匹配的点


      旧答案保留以防对搜索有用。

      if(master.indexOf(sub) > -1){ //Do awesome stuff }

      重要的是要记住,这只会匹配 master 字面引用 sub。如果它只包含一个内容相同的数组,但引用了不同的特定对象,则不匹配。

      【讨论】:

        【解决方案10】:

        如果顺序很重要,它必须是一个实际的子数组(而不是数组的子集),如果值是严格的整数,那么试试这个

        console.log ( master.join(",").indexOf( subarray.join( "," ) ) == -1 )
        

        只检查值检查这个fiddle(不使用第三方库)

        var master = [12, 44, 22, 66, 222, 777, 22, 22, 22, 6, 77, 3]; 
        
        var sub = [777, 22, 22]; 
        
        function isSubset( arr1, arr2 )
        {
            for (var i=0; i<arr2.length; i++)
            {
                if ( arr1.indexOf( arr2[i] ) == -1 )
                {
                  return false;
                }
            }
            return true;
        }
        console.log( isSubset( master, sub ) );
        

        here 也解释了更快的选项。

        【讨论】:

        • @zerkms 为什么这么说?这是工作。它输出“真”
        • 好吧,对于我的例子,它应该返回false
        • @zerkms 明白了。把你的观点。现在正在尝试提出一个可以处理相同值的多个实例的方法。
        猜你喜欢
        • 2012-01-09
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-03-10
        • 2018-07-13
        • 1970-01-01
        相关资源
        最近更新 更多