ターゲット配列があり["apple","banana","orange"]
、他の配列にターゲット配列要素のいずれかが含まれているかどうかを確認したい。
例えば:
["apple","grape"] //returns true;
["apple","banana","pineapple"] //returns true;
["grape", "pineapple"] //returns false;
JavaScriptでそれを行うにはどうすればよいですか?
ターゲット配列があり["apple","banana","orange"]
、他の配列にターゲット配列要素のいずれかが含まれているかどうかを確認したい。
例えば:
["apple","grape"] //returns true;
["apple","banana","pineapple"] //returns true;
["grape", "pineapple"] //returns false;
JavaScriptでそれを行うにはどうすればよいですか?
回答:
バニラ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を返します。
true
、配列の要素のいずれかがテスト関数を通過するかどうかを返します。それ以外の場合はを返しますfalse
。
[false, false, false]
空の配列ではないことが予想され[]
ますか?
/**
* @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;
});
};
some()
radです。何かが一致するとすぐに終了します。
arr.some(v=> haystack.indexOf(v) >= 0)
arr.some(v => haystack.includes(v))
arr1.some(v => arr2.indexOf(v) >= 0)
。
includes
:どうやらそれはIEでサポートされていないとして、stackoverflow.com/questions/36574351/...
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]
交差関数は、一致したアイテムを含む新しい配列を返し、一致しない場合は空の配列を返します。
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
型強制が必要ない場合(の使用のため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つのにターゲットに対して一致ます。
もちろん、使用したいものは何でも数字と入れ替えることができます。例のように、文字列は問題ありません。
そして、私の具体的な例では、結果はtrue
2番目の配列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/
このソリューションの欠点は、値が(暗黙的に)文字列に変換され、ルックアップマップのキーとして設定されるため、数値と文字列(およびブール値)のみを(正しく)使用できることです。これは、リテラル以外の値に対して正確に/可能/簡単に行われるわけではありません。
undefined
...それが何の!!
ためにあるのか」-それは間違っています。のブール値の反対を返し!
ます。
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) );
参考になれば幸いです。
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"]));
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));
};
indexOf
とを使用してソリューションを投稿し続けincludes
ますが、Set
EcmaScriptに導入されてから4年後にネイティブを使用する、より効率的なセットベースのソリューションであなたが最初に答えます。+1
この短くて甘い構文は、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を出力します
今後ともよろしくお願いいたします。
これは私が共有すべきだと思った興味深いケースです。
オブジェクトの配列と選択されたフィルターの配列があるとします。
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'] }
// ]
私は3つのソリューションを書きました。基本的に彼らは同じことをします。彼らは得るとすぐに真を返しますtrue
。私は、3つの異なる方法を示すためだけに3つのソリューションを作成しました。今、それはあなたがもっと好きなものに依存します。あなたはperformance.now()を使うことができますを使用して、いずれかのソリューションのパフォーマンスを確認。私のソリューションでは、操作をより効率的にするために、最大の配列と最小の配列もチェックしています。
3番目の解決策は最も可愛くないかもしれませんが、効率的です。一部のコーディング面接では組み込みメソッドの使用が許可されていないため、これを追加することにしました。
最後に、確かに... 2つのNESTED forループ(ブルートフォースの方法)を使用した解決策を考え出すことができますが、時間の複雑さが悪いO(n ^ 2)であるため、それを避けたいです。
注意:
.includes()
他の人がしたように使う代わりに、あなたは使うことができます.indexOf()
。値が0より大きいかどうかを確認するだけです。値が存在しない場合は、-1になります。存在する場合は、0より大きい値になります。
どちらがより良い性能を持っていますか?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でもないので、私が言ったことに誤りがある場合はお知らせください。
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と述語で置き換えることができます。
私の解決策は、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;
これは、メイン配列を繰り返し処理して、他の配列にターゲット要素が含まれているかどうかを確認するだけで実行できます。
これを試して:
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));
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
indexOf
と私は反対に思います:) 一方、外部ライブラリが本当に必要ない場合は追加しないようにすることに同意しますが、それにはあまりこだわっていません。サードパーティのライブラリは、便利な機能だけでなく、充実した機能も提供します。例:すべてのエッジケースと市長のブラウザーをソリューションでテストしましたか?(ちなみに、every
リストでインデックスを検索するのではなく、リストのすべての要素で何かを評価しています)
免責事項:多くの人はこれに強く反対するでしょう。本当に問題になるのは、ライブラリが同じ名前のプロトタイプ関数(動作が異なる)またはそのようなものを追加した場合だけでした。
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
以前のいくつかのアプローチの問題は、すべての単語を正確に一致させる必要があることです。しかし、部分一致の結果を提供したい場合はどうなりますか?
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"]
これは、ユーザーが単語を入力し、結果にそれらの単語を任意の順序、位置、大文字と小文字で含めることができる検索ボックスを提供する場合に便利です。
@Paul Grimshawの回答を更新し、読みやすくするためにincludes
insteedの使用indexOf
let found = arr1.some(r => arr2.indexOf(r)> = 0)
let found = arr1.some(r => arr2.includes(r))
個人的には、次の関数を使用します。
var arrayContains = function(array, toMatch) {
var arrayAsString = array.toString();
return (arrayAsString.indexOf(','+toMatch+',') >-1);
}
"toString()"メソッドは常にコンマを使用して値を区切ります。本当にプリミティブ型でのみ機能します。
.find()へのネストされた呼び出しを伴う配列.filter()は、2番目の配列のメンバーである最初の配列のすべての要素を返します。返された配列の長さをチェックして、2番目の配列のいずれかが最初の配列にあったかどうかを判別します。
getCommonItems(firstArray, secondArray) {
return firstArray.filter((firstArrayItem) => {
return secondArray.find((secondArrayItem) => {
return firstArrayItem === secondArrayItem;
});
});
}
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);
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;
for
ループを使用して、ターゲット配列を反復処理します。すべての要素は、現在の配列(使用中に含まれている場合はcurrent.indexOf(elem) !== -1)
、それらはすべてそこにいる。