web-dev-qa-db-ja.com

Javascript配列にはサブ配列が含まれます/含まれます

配列に別の配列が含まれているかどうかを確認する必要があります。サブアレイの順序は重要ですが、実際のオフセットは重要ではありません。これは次のようになります。

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

var sub = [777, 22, 22]; 

したがって、mastersubが含まれているかどうかを知りたいのです。

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

では、これをエレガントで効率的な方法でどのように行うことができますか?

10
Victor Axelsson

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]));
6
Nina Scholz

ちょっと考えただけですが、効率はアレイのサイズに依存します

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
}
4
Mahesh Talada

[〜#〜]編集[〜#〜]

最初は誤解された質問。

_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を参照する場合にのみ一致することを覚えておくことが重要です。同じ内容の配列が含まれているだけで、異なる特定のオブジェクトを参照している場合、一致しません。

1
Mild Fuzz

順序が重要な場合は、実際にはサブ配列(配列のサブセットではない)である必要があり、値が厳密に整数である場合は、これを試してください。

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

説明されているより速いオプションがあります ここ も。

1
gurvinder372

このように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;
}

ここ

UPDATED:マスター内のサブ配列のインデックスを返します(サブ配列のカバー順序)

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

デモ: ここ

0
Nguyen Tran

同様の問題があり、セットを使用して解決しました。

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

この答えのために、私はサブ配列の順序を保持しています。つまり、サブ配列の要素は連続した順序である必要があります。マスターとの比較中に余分な要素がある場合、それはfalseになります。

私は3つのステップでそれをやっています:

  1. sub内のmasterの最初の要素のインデックスを見つけて、配列matched_index[]に格納します。
  2. matched_index[]の各エントリについて、subの各要素がs_indexから始まるmasterと同じであるかどうかを確認します。一致しない場合は、falseを返し、subのforループを中断し、matched_index[]の次の要素の次のforループを開始します。
  3. いつでも、同じsub配列がmasterで見つかった場合、ループは中断され、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]));
0
Jaimin Patel

以下のこのスニペットを実行すると、機能するはずです

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

編集:@AlexanderGromnitskyあなたは正しいですこのコードは正しくありません、そしてキャッチしてくれてありがとう!上記のコードは、実際にはopが要求したことを実行しません。私は質問を十分に詳しく読んでおらず、このコードは順序を無視しています。 1年後、ここに私が思いついたものがあり、うまくいけば、これが誰かを助けるかもしれません。

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でない限り重要ではありません。

0
Matt Dabit