JavaScriptで配列に別の配列の要素が含まれているかどうかを確認する


406

ターゲット配列があり["apple","banana","orange"]、他の配列にターゲット配列要素のいずれかが含まれているかどうかを確認したい。

例えば:

["apple","grape"] //returns true;

["apple","banana","pineapple"] //returns true;

["grape", "pineapple"] //returns false;

JavaScriptでそれを行うにはどうすればよいですか?


3
forループを使用して、ターゲット配列を反復処理します。すべての要素は、現在の配列(使用中に含まれている場合はcurrent.indexOf(elem) !== -1)、それらはすべてそこにいる。
ブレンダー

21
@Alexは回答者を選択します。回答を未チェックのままにしておくのは失礼です。特に、この多くの良い回答についてはそうです。私があなただったら、アンダースコア/ロダッシュを選びます。
Leon Gaban

1
@LeonGaban同意しない。この操作を実行するためだけにライブラリをインポートすることはしません。
devpato

2
@devpatoええ、私の考えが変わりました。ES6ソリューションは私のお気に入りです
Leon Gaban

arr1.some(el1 => arr2.includes(el1));はどうですか??
Walaszka

回答:


551

バニラJS

ES2016:

const found = arr1.some(r=> arr2.includes(r))

ES6:

const found = arr1.some(r=> arr2.indexOf(r) >= 0)

使い方

some(..)配列の各要素をテスト関数と照合し、配列の要素のいずれかがテスト関数に合格した場合はtrueを返し、そうでない場合はfalseを返します。indexOf(..) >= 0またincludes(..)、指定された引数が配列に存在する場合、どちらもtrueを返します。


48
このコードには説明が必要です-これはうまくいくかもしれませんが、誰も何も学習していないので価値はありません
TolMera

6
Array.prototype.some()は、配列の各要素をテスト関数と照合しtrue、配列の要素のいずれかがテスト関数を通過するかどうかを返します。それ以外の場合はを返しますfalse
ヘンデカ2017

2
これは正解です!ES6を使用した素晴らしいもの
ナチョ

1
私の結果は[false, false, false]空の配列ではないことが予想され[]ますか?
バットマン

@バットマン:結果はtrue / falseですが、skyisred氏のソリューションを適用できます
0zkr PM

230

バニラjs

/**
 * @description determine if an array contains one or more items from another array.
 * @param {array} haystack the array to search.
 * @param {array} arr the array providing items to check for in the haystack.
 * @return {boolean} true|false if haystack contains at least one item from arr.
 */
var findOne = function (haystack, arr) {
    return arr.some(function (v) {
        return haystack.indexOf(v) >= 0;
    });
};

10
素敵な解決策! some()radです。何かが一致するとすぐに終了します。
averydev 2016年

6
このようなイベントtidier:arr.some(v=> haystack.indexOf(v) >= 0)
ポールGrimshaw

85
ES2016でも利用可能arr.some(v => haystack.includes(v))
loganfsmyth

5
一行にarr1.some(v => arr2.indexOf(v) >= 0)
webjay

1
今のところ、それは使用を避けるのが最善かもしれませんincludes:どうやらそれはIEでサポートされていないとして、stackoverflow.com/questions/36574351/...
Shafiqueジャマール

72

librayの使用に反対していない場合は、http://underscorejs.org/に共通化メソッドがあり、これによりこれを簡略化できます。

var _ = require('underscore');

var target = [ 'apple', 'orange', 'banana'];
var fruit2 = [ 'apple', 'orange', 'mango'];
var fruit3 = [ 'mango', 'lemon', 'pineapple'];
var fruit4 = [ 'orange', 'lemon', 'grapes'];

console.log(_.intersection(target, fruit2)); //returns [apple, orange]
console.log(_.intersection(target, fruit3)); //returns []
console.log(_.intersection(target, fruit4)); //returns [orange]

交差関数は、一致したアイテムを含む新しい配列を返し、一致しない場合は空の配列を返します。


3
これを何度か使用しましたが、問題は、交差全体を生成するためではなく、他の配列に要素が存在するかどうかを確認することでした。パフォーマンスの点では、配列が大きい場合は大きな違いがあります。最初のケースでは、1つの一致が見つかるとすぐに救済できるためです。
JHH 2016年

1
lodashはバニラJavascriptよりはるかに読みやすく、Ramdaのようなライブラリは常にバニラimhoの代わりに使用する必要があります。すべての開発者にとってより良い...
Leon Gaban

52

ES6(最速)

const a = ['a', 'b', 'c'];
const b = ['c', 'a', 'd'];
a.some(v=> b.indexOf(v) !== -1)

ES2016

const a = ['a', 'b', 'c'];
const b = ['c', 'a', 'd'];
a.some(v => b.includes(v));

下線

const a = ['a', 'b', 'c'];
const b = ['c', 'a', 'd'];
_.intersection(a, b)

デモ: https //jsfiddle.net/r257wuv5/

jsPerf:https ://jsperf.com/array-contains-any-element-of-another-array


1
これは最もシンプルで宣言的な解決策です
strider

私は本当にこれに遅れていることを知っていますが、JSFiddleがJQuery Edgeを追加してFirebug Liteをオンにしているかどうかコンソールを確認するには
Rojo

JSperfリンクの破損
DarckBlezzer

時間と空間の複雑さに違いはありますか?複雑さに関して最善の解決策は何でしょうか?
ナチョ

41

型強制が必要ない場合(の使用のためindexOf)、次のようなことを試すことができます。

var arr = [1, 2, 3];
var check = [3, 4];

var found = false;
for (var i = 0; i < check.length; i++) {
    if (arr.indexOf(check[i]) > -1) {
        found = true;
        break;
    }
}
console.log(found);

arrターゲットアイテムが含まれる場所。最後にfound、2番目のアレイに少なくとも1つのにターゲットに対して一致ます。

もちろん、使用したいものは何でも数字と入れ替えることができます。例のように、文字列は問題ありません。

そして、私の具体的な例では、結果はtrue2番目の配列3がターゲットに存在するためです。


更新:

これを関数に整理する方法を以下に示します(以前のいくつかの小さな変更を加えて):

var anyMatchInArray = (function () {
    "use strict";

    var targetArray, func;

    targetArray = ["apple", "banana", "orange"];
    func = function (checkerArray) {
        var found = false;
        for (var i = 0, j = checkerArray.length; !found && i < j; i++) {
            if (targetArray.indexOf(checkerArray[i]) > -1) {
                found = true;
            }
        }
        return found;
    };

    return func;
}());

デモ: http : //jsfiddle.net/u8Bzt/

この場合、関数を変更してtargetArray、クロージャーにハードコードするのではなく、引数として渡すことができます。


UPDATE2:

上記の私の解決策は機能し、(できればもっと)読みやすいかもしれませんが、私が説明した概念を処理するための「より良い」方法は、少し異なる方法で行うことだと思います。上記のソリューションの「問題」はindexOf、ループの内側で、ターゲット配列が他の配列のすべてのアイテムに対して完全にループされることです。これは、「ルックアップ」(マップ... JavaScriptオブジェクトリテラル)を使用して簡単に「修正」できます。これにより、各アレイで2つの単純なループが可能になります。次に例を示します。

var anyMatchInArray = function (target, toMatch) {
    "use strict";

    var found, targetMap, i, j, cur;

    found = false;
    targetMap = {};

    // Put all values in the `target` array into a map, where
    //  the keys are the values from the array
    for (i = 0, j = target.length; i < j; i++) {
        cur = target[i];
        targetMap[cur] = true;
    }

    // Loop over all items in the `toMatch` array and see if any of
    //  their values are in the map from before
    for (i = 0, j = toMatch.length; !found && (i < j); i++) {
        cur = toMatch[i];
        found = !!targetMap[cur];
        // If found, `targetMap[cur]` will return true, otherwise it
        //  will return `undefined`...that's what the `!!` is for
    }

    return found;
};

デモ: http : //jsfiddle.net/5Lv9v/

このソリューションの欠点は、値が(暗黙的に)文字列に変換され、ルックアップマップのキーとして設定されるため、数値と文字列(およびブール値)のみを(正しく)使用できることです。これは、リテラル以外の値に対して正確に/可能/簡単に行われるわけではありません。


2
優れた例、2番目の例は単に素晴らしいです。
Sorin Haidau 2014

someまたはfindIndexを使用できるのに、なぜforループを使用しているのですか?
それは私です...アレックス

1
「一部」はコードを大幅に簡略化します。また、anyMatchInArray([1,2,3、 "cats"、 "4"]、["1"、4])はtrueになります。最後に、これは、ルックアップの数が多く、targetMapをキャッシュした場合に、パフォーマンスが向上する可能性があります。それでも、パフォーマンスが向上する可能性があります。例えば、私はそれを推測「が見つかり= toMatch [i]を==未定義!」よりパフォーマンスこと、そして考え、より良いいくつかのケースでは(あなたがfalseに「評価」または0しないこと)
csga5000

「さもなければそれは戻るでしょうundefined...それが何の!!ためにあるのか」-それは間違っています。のブール値の反対を返し!ます。
AlienWebguy 2017

41

ES6ソリューション:

let arr1 = [1, 2, 3];
let arr2 = [2, 3];

let isFounded = arr1.some( ai => arr2.includes(ai) );

それとは異なり:すべての値を含む必要があります。

let allFounded = arr2.every( ai => arr1.includes(ai) );

参考になれば幸いです。


array1からarra2値のインデックスを取得する方法はありますか?
Anzil khaN

1
その場合、「some」の代わりに「filter」を使用できます。次に、ブール値ではなく配列を返し、そこから簡単に値にアクセスできます。
tanvir993

29

あなたはlodashを使用して行うことができます:

_.intersection(originalTarget, arrayToCheck).length > 0

集合の交差は、同じ要素の配列を生成する両方のコレクションで行われます。


この問題では最初の一致を見つけるだけで十分ですが、最初の一致を見つけたintersection後でも比較を続けてすべてを見つけるため、パフォーマンスの点で最適ではありません。filterちょうど必要なときに使用するようなものですfind
アレクサンダー

29

filter / indexOfの使用:

function containsAny(source,target)
{
    var result = source.filter(function(item){ return target.indexOf(item) > -1});   
    return (result.length > 0);  
}    


//results

var fruits = ["apple","banana","orange"];


console.log(containsAny(fruits,["apple","grape"]));

console.log(containsAny(fruits,["apple","banana","pineapple"]));

console.log(containsAny(fruits,["grape", "pineapple"]));


これは、_。intersectionなどのライブラリ関数と同じ問題に悩まされています。小さな配列の場合、明らかにそれは問題ではありません。
JHH 2016年

13
const areCommonElements = (arr1, arr2) => {
    const arr2Set = new Set(arr2);
    return arr1.some(el => arr2Set.has(el));
};

または、最初にこれらの2つの配列のどちらが長いかを見つけ、最短のSet配列にsomeメソッドを適用しながら、最長の配列を作ると、パフォーマンスが向上する場合もあります。

const areCommonElements = (arr1, arr2) => {
    const [shortArr, longArr] = (arr1.length < arr2.length) ? [arr1, arr2] : [arr2, arr1];
    const longArrSet = new Set(longArr);
    return shortArr.some(el => longArrSet.has(el));
};

3
人々はネストindexOfとを使用してソリューションを投稿し続けincludesますが、SetEcmaScriptに導入されてから4年後にネイティブを使用する、より効率的なセットベースのソリューションであなたが最初に答えます。+1
トリンコット

9

この短くて甘い構文は、2つの配列間のすべてまたは一部の要素に一致することがわかりました。例えば

// OR演算。array2要素のいずれかがarray1に存在するかどうかを確認します。これは、最初の一致があるとすぐに戻ります。関数がTRUEを返すと、一部のメソッドが中断します。

let array1 = ['a', 'b', 'c', 'd', 'e'], array2 = ['a', 'b'];

console.log(array2.some(ele => array1.includes(ele)));

// TRUEを出力します

// AND演算。すべてのarray2要素がarray1に存在するかどうかを確認します。これは、関数がTRUEを返すときに一部のメソッドが中断するため、最初の一致がなくなるとすぐに返されます

let array1 = ['a', 'b', 'c', 'd', 'e'], array2 = ['a', 'x'];

console.log(!array2.some(ele => !array1.includes(ele)));

// FALSEを出力します

今後ともよろしくお願いいたします。


ES5で機能させるために、質問の2番目の部分が本当に気に入りました。次のようにしました。
フリースガード

6

ネストされたArray.prototype.some呼び出しを使用できます。これには、完全にネストされたループを実行する他のソリューションではなく、最初の一致時に保釈されるという利点があります。

例えば。

var arr = [1, 2, 3];
var match = [2, 4];

var hasMatch = arr.some(a => match.some(m => a === m));

4

これは私が共有すべきだと思った興味深いケースです。

オブジェクトの配列と選択されたフィルターの配列があるとします。

let arr = [
  { id: 'x', tags: ['foo'] },
  { id: 'y', tags: ['foo', 'bar'] },
  { id: 'z', tags: ['baz'] }
];

const filters = ['foo'];

選択したフィルターをこの構造に適用するために、

if (filters.length > 0)
  arr = arr.filter(obj =>
    obj.tags.some(tag => filters.includes(tag))
  );

// [
//   { id: 'x', tags: ['foo'] },
//   { id: 'y', tags: ['foo', 'bar'] }
// ]

4

私は3つのソリューションを書きました。基本的に彼らは同じことをします。彼らは得るとすぐに真を返しますtrue。私は、3つの異なる方法を示すためだけに3つのソリューションを作成しました。今、それはあなたがもっと好きなものに依存します。あなたはperformance.now()を使うことができますを使用して、いずれかのソリューションのパフォーマンスを確認。私のソリューションでは、操作をより効率的にするために、最大の配列と最小の配列もチェックしています。

3番目の解決策は最も可愛くないかもしれませんが、効率的です。一部のコーディング面接では組み込みメソッドの使用が許可されていないため、これを追加することにしました。

最後に、確かに... 2つのNESTED forループ(ブルートフォースの方法)を使用した解決策を考え出すことができますが、時間の複雑さが悪いO(n ^ 2)であるため、それを避けたいです。

注意:

.includes()他の人がしたように使う代わりに、あなたは使うことができます .indexOf()。値が0より大きいかどうかを確認するだけです。値が存在しない場合は、-1になります。存在する場合は、0より大きい値になります。

indexOf()とinclude()

どちらがより良い性能を持っていますか?indexOf()少しですが、インクルードは私の意見ではより読みやすくなっています。

私が誤解.includes()しておらずindexOf()、舞台裏でループを使用している場合、それらをで使用するとO(n ^ 2)になり.some()ます。

ループの使用

 const compareArraysWithIncludes = (arr1, arr2) => {
     const [smallArray, bigArray] =
        arr1.length < arr2.length ? [arr1, arr2] : [arr2, arr1];

     for (let i = 0; i < smallArray.length; i++) {
       return bigArray.includes(smallArray[i]);
     }

      return false;
    };

.some()の使用

const compareArraysWithSome = (arr1, arr2) => {
  const [smallArray, bigArray] =
    arr1.length < arr2.length ? [arr1, arr2] : [arr2, arr1];
  return smallArray.some(c => bigArray.includes(c));
};

マップの使用 時間の複雑さ O(2n)=> O(n)

const compararArraysUsingObjs = (arr1, arr2) => {
  const map = {};

  const [smallArray, bigArray] =
    arr1.length < arr2.length ? [arr1, arr2] : [arr2, arr1];

  for (let i = 0; i < smallArray.length; i++) {
    if (!map[smallArray[i]]) {
      map[smallArray[i]] = true;
    }
  }

  for (let i = 0; i < bigArray.length; i++) {
    if (map[bigArray[i]]) {
      return true;
    }
  }

  return false;
};

私のコード: stackblitz

私はパフォーマンスの専門家でもBigOでもないので、私が言ったことに誤りがある場合はお知らせください。


3

some / findIndexとindexOfの組み合わせについてはどうですか?

だからこのようなもの:

var array1 = ["apple","banana","orange"];
var array2 = ["grape", "pineapple"];

var found = array1.some(function(v) { return array2.indexOf(v) != -1; });

読みやすくするために、この機能をArrayオブジェクト自体に追加できます。

Array.prototype.indexOfAny = function (array) {
    return this.findIndex(function(v) { return array.indexOf(v) != -1; });
}

Array.prototype.containsAny = function (array) {
    return this.indexOfAny(array) != -1;
}

注:述語で何かしたい場合は、内部のindexOfを別のfindIndexと述語で置き換えることができます。


3

私の解決策は、Array.prototype.some()およびArray.prototype.includes()配列ヘルパーを適用します。

ES6

const originalFruits = ["apple","banana","orange"];

const fruits1 = ["apple","banana","pineapple"];

const fruits2 = ["grape", "pineapple"];

const commonFruits = (myFruitsArr, otherFruitsArr) => {
  return myFruitsArr.some(fruit => otherFruitsArr.includes(fruit))
}
console.log(commonFruits(originalFruits, fruits1)) //returns true;
console.log(commonFruits(originalFruits, fruits2)) //returns false;


originalFruitsからインクルードアイテムのインデックスを取得する方法はありますか?
Anzil khaN

3

もう1つのソリューション

var a1 = [1, 2, 3, 4, 5]
var a2 = [2, 4]

a1にa2のすべての要素が含まれているかどうかを確認します

var result = a1.filter(e => a2.indexOf(e) !== -1).length === a2.length
console.log(result)

2

これは、メイン配列を繰り返し処理して、他の配列にターゲット要素が含まれているかどうかを確認するだけで実行できます。

これを試して:

function Check(A) {
    var myarr = ["apple", "banana", "orange"];
    var i, j;
    var totalmatches = 0;
    for (i = 0; i < myarr.length; i++) {
        for (j = 0; j < A.length; ++j) {
            if (myarr[i] == A[j]) {

                totalmatches++;

            }

        }
    }
    if (totalmatches > 0) {
        return true;
    } else {
        return false;
    }
}
var fruits1 = new Array("apple", "grape");
alert(Check(fruits1));

var fruits2 = new Array("apple", "banana", "pineapple");
alert(Check(fruits2));

var fruits3 = new Array("grape", "pineapple");
alert(Check(fruits3));

JSFIDDLEでのデモ


2

underscorejs

var a1 = [1,2,3];
var a2 = [1,2];

_.every(a1, function(e){ return _.include(a2, e); } ); //=> false
_.every(a2, function(e){ return _.include(a1, e); } ); //=> true

2
個人的には、私はunderscorejsが好きですが、これは複雑なコードがどのように見えるかの古典的な例です。underscorejsコードとして理解するのが難しいだけでなく、一般的なコーディングの観点からも同じことが当てはまります(たとえば、配列内の何かのインデックスを検索するときに、「すべて」という単語は思い浮かびませんが、 「indexOf」はします)。数文字の追加で純粋なJavaScriptソリューションを提供できる場合は、サードパーティツールを不必要に使用しないでください。そのためにunderscorejsを使用するということは、ソリューションがサードパーティのコードと密接に結合することを意味します。
csharpforevermore 2015年

@csharpforevermoreこれは好みの問題だと思いますが、このソリューションは他のすべてのソリューションよりも複雑であるindexOfと私は反対に思います:) 一方、外部ライブラリが本当に必要ない場合は追加しないようにすることに同意しますが、それにはあまりこだわっていません。サードパーティのライブラリは、便利な機能だけでなく、充実した機能も提供します。例:すべてのエッジケースと市長のブラウザーをソリューションでテストしましたか?(ちなみに、everyリストでインデックスを検索するのではなく、リストのすべての要素で何かを評価しています)
fguillen

2

配列プロトタイプへの追加

免責事項:多くの人はこれに強く反対するでしょう。本当に問題になるのは、ライブラリが同じ名前のプロトタイプ関数(動作が異なる)またはそのようなものを追加した場合だけでした。

コード:

Array.prototype.containsAny = function(arr) {
    return this.some(
        (v) => (arr.indexOf(v) >= 0)
    )
}

大きな矢印関数を使用しない場合:

Array.prototype.containsAny = function(arr) {
    return this.some(function (v) {
        return arr.indexOf(v) >= 0
    })
}

使用法

var a = ["a","b"]

console.log(a.containsAny(["b","z"]))    // Outputs true

console.log(a.containsAny(["z"]))    // Outputs false

2

部分一致で大文字と小文字を区別しないバニラJS

以前のいくつかのアプローチの問題は、すべての単語を正確に一致させる必要があることです。しかし、部分一致の結果を提供したい場合はどうなりますか?

function search(arrayToSearch, wordsToSearch) {
    arrayToSearch.filter(v => 
        wordsToSearch.every(w => 
            v.toLowerCase().split(" ").
                reduce((isIn, h) => isIn || String(h).indexOf(w) >= 0, false)
            )
        )
}
//Usage
var myArray = ["Attach tag", "Attaching tags", "Blah blah blah"];
var searchText = "Tag attach";
var searchArr = searchText.toLowerCase().split(" "); //["tag", "attach"]

var matches = search(myArray, searchArr);
//Will return
//["Attach tag", "Attaching tags"]

これは、ユーザーが単語を入力し、結果にそれらの単語を任意の順序、位置、大文字と小文字で含めることができる検索ボックスを提供する場合に便利です。


2

@Paul Grimshawの回答を更新し、読みやすくするためにincludesinsteedの使用indexOf

let found = arr1.some(r => arr2.indexOf(r)> = 0)
let found = arr1.some(r => arr2.includes(r))


1

私はこのようなアンダースコアのjsを使用してノードで解決策を思い付きました:

var checkRole = _.intersection(['A','B'], ['A','B','C']);
if(!_.isEmpty(checkRole)) { 
     next();
}

0

個人的には、次の関数を使用します。

var arrayContains = function(array, toMatch) {
    var arrayAsString = array.toString();
    return (arrayAsString.indexOf(','+toMatch+',') >-1);
}

"toString()"メソッドは常にコンマを使用して値を区切ります。本当にプリミティブ型でのみ機能します。


2
これは、要素が配列の先頭または末尾にあるか、順序が異なる場合は機能しません。
DanielM

1
ダニエルが言ったようにこれは壊れているので-1。回避策としてarrayAsStringにコンマを付加して追加することもできますが、正直なところ、文字列を使用するための過度に複雑なソリューションのように思えます。
JHH 2016年

0

.find()へのネストされた呼び出しを伴う配列.filter()は、2番目の配列のメンバーである最初の配列のすべての要素を返します。返された配列の長さをチェックして、2番目の配列のいずれかが最初の配列にあったかどうかを判別します。

getCommonItems(firstArray, secondArray) {
  return firstArray.filter((firstArrayItem) => {
    return secondArray.find((secondArrayItem) => {
      return firstArrayItem === secondArrayItem;
    });
  });
}

アレイを「クリーン」にする方法はありますか?最初の配列に値が存在する場合、2番目の配列の値を削除するようなものですか?
sandrooco 2017年

0
console.log("searching Array: "+finding_array);
console.log("searching in:"+reference_array);
var check_match_counter = 0;
for (var j = finding_array.length - 1; j >= 0; j--) 
{
    if(reference_array.indexOf(finding_array[j]) > 0)
    {
        check_match_counter = check_match_counter + 1;
    }
}
 var match = (check_match_counter > 0) ? true : false;
console.log("Final result:"+match);

0
var target = ["apple","banana","orange"];
var checkArray = ["apple","banana","pineapple"];

var containsOneCommonItem = target.some(x => checkArray.some(y => y === x));`

["apple","grape"] //returns true;

["apple","banana","pineapple"] //returns true;

["grape", "pineapple"] //returns false;
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.