2つの配列の値が同じかどうかを知る方法


104

私はこれら2つの配列を持っています。1つはajaxリクエストからの情報で満たされ、もう1つはユーザーがクリックしたボタンを格納します。私はこのコードを使用します(サンプル番号を入力しました):

var array1 = [2, 4];
var array2 = [4, 2]; //It cames from the user button clicks, so it might be disordered.
array1.sort(); //Sorts both Ajax and user info.
array2.sort();
if (array1==array2) {
    doSomething();
}else{
    doAnotherThing();
}

ただしfalse、2つの配列が同じでも名前が異なる場合でも、常にが返されます。(私はこれをChromeのJS Consoleで確認しました)。では、これら2つの配列に同じものが含まれているかどうかを知る方法はありますか?なぜそれは与えるのfalseですか?最初の配列のどの値が2番目の配列にないかをどのようにして知ることができますか?


1
配列の各要素を確認する必要があると確信しています。
Thomas Li

それがfalseを返す理由を知っていますか?奇妙な。
RobW 2014年


回答:


36
function arraysEqual(_arr1, _arr2) {

    if (!Array.isArray(_arr1) || ! Array.isArray(_arr2) || _arr1.length !== _arr2.length)
      return false;

    var arr1 = _arr1.concat().sort();
    var arr2 = _arr2.concat().sort();

    for (var i = 0; i < arr1.length; i++) {

        if (arr1[i] !== arr2[i])
            return false;

    }

    return true;

}

前の回答とは異なり、これは元の配列を変更しないことに注意してください。


2
ソートにはnlog(n)時間かかります。並べ替えは必要ありません。この回答stackoverflow.com/a/55614659/3209523は線形時間で動作します。
canbax

typescriptを使用すると、Array.isArray()でエラーが発生し、正常に機能することがなくなりました。
アリエルフリッシャー

88

配列項目がオブジェクトでない場合-たとえば、数値または文字列の場合、結合された文字列を比較して、同じメンバーが任意の順序であるかどうかを確認できます-

var array1= [10, 6, 19, 16, 14, 15, 2, 9, 5, 3, 4, 13, 8, 7, 1, 12, 18, 11, 20, 17];
var array2= [12, 18, 20, 11, 19, 14, 6, 7, 8, 16, 9, 3, 1, 13, 5, 4, 15, 10, 2, 17];

if(array1.sort().join(',')=== array2.sort().join(',')){
    alert('same members');
}
else alert('not a match');

2
これは、一意に識別するtoString値を持つプリミティブまたはオブジェクトに対しては適切に機能しますが、オブジェクトに対しては機能しません。
devios1

ありがとう!きちんとした解決策
Gaston Sanchez

3
nullアイテムと並べ替えに注意してください。私の場合、「、2,2,3」と「2,2,3」のように比較する文字列がありましたが、これらはもちろん厳密には同じではありません。
barbara.post 2015

2
文字列、つまり['a', 'b']とで失敗する可能性があります['a,b']。この手法は、使い捨ての小さなスクリプトにのみお勧めします。
アレックス

1
@alex-私の場合、文字列ではカンマが許可されていますが、セミコロンは許可されていないため、「;」を使用しました。コンマの代わりに参加する
a2345

45

2つの配列に同じ値があるかどうかだけを確認したい場合は(各値の出現数と順序に関係なく)、lodashを使用してこれを行うことができます。

_.isEmpty(_.xor(array1, array2))

短く、シンプルでかわいい!


1
xorはアンダースコアのドキュメントで見つけることができないようですか?IODashをお考えですか?
Patrick Mencias-lewis、2015

44
Array.prototype.compare = function(testArr) {
    if (this.length != testArr.length) return false;
    for (var i = 0; i < testArr.length; i++) {
        if (this[i].compare) { //To test values in nested arrays
            if (!this[i].compare(testArr[i])) return false;
        }
        else if (this[i] !== testArr[i]) return false;
    }
    return true;
}

var array1 = [2, 4];
var array2 = [4, 2];
if(array1.sort().compare(array2.sort())) {
    doSomething();
} else {
    doAnotherThing();
}

多分?


ありがとうございました!期待どおりに動作します。関数を少し変更して、ミスマッチの数もわかるようにしました。
Carlos Precioso、2011年

[2,4] [4,2]の場合はfalse。
Suraz Khanal 2016

@SurazKhanalまだソートする必要があります
アーロン

26

コードが機能しなかった理由

JavaScriptには、プリミティブデータタイプと非プリミティブデータタイプがあります。

プリミティブデータタイプの場合、バーの両側のものが同じ値であるかどうか=====確認します。それ1 === 1が本当の理由です。

配列などの非プリミティブデータ型の場合、参照の等価性=====確認します。それは、彼らがいるかどうか確認し、あるarr1arr2同じオブジェクトです。あなたの例では、2つの配列は同じオブジェクトを同じ順序で持っていますが、同等ではありません。

ソリューション

2つの配列arr1とはarr2、次の場合に限り同じメンバーになります。

  • のすべてarr2arr1

そして

  • のすべてarr1arr2

したがって、これでうまくいきます(ES2016):

const containsAll = (arr1, arr2) => 
                arr2.every(arr2Item => arr1.includes(arr2Item))

const sameMembers = (arr1, arr2) => 
                        containsAll(arr1, arr2) && containsAll(arr2, arr1);

sameMembers(arr1, arr2); // `true`

Underscoreを使用したこの2番目のソリューションは、あなたがやろうとしていたことにより近いものです。

arr1.sort();
arr2.sort();

_.isEqual(arr1, arr2); // `true`

これisEqualは、「深い同等性」をチェックするために機能します。つまり、参照の同等性以上のものを調べ、値を比較します。

3番目の質問に対する解決策

また、arr1に含まれていないものを見つける方法を尋ねましたarr2

これでうまくいきます(ES2015):

const arr1 = [1, 2, 3, 4];
const arr2 = [3, 2, 1];

arr1.filter(arr1Item => !arr2.includes(arr1Item)); // `[4]`

Underscoreのdifference:メソッドを使用することもできます。

_.difference(arr1, arr2); // `[4]`

更新

@Reduのコメントを参照してください—私の解決策はのためのsameMembersものですが、あなたが心に留めているかもしれないものはとしてsameMembersInOrderも知られていdeepEqualsます。

アップデート2

配列のメンバーの順序を気にしない場合は、ES2015 +のSet方がより適切なデータ構造になる可能性がありますArray。危険なモンキーパッチを実装isSupersetおよびdifference使用する方法については、MDNのメモを参照してください。


1
あなたの解決策は間違っています。「2つの配列arr1とarr2は、arr2のすべてがarr1にあり、かつarr1のすべてがarr2にある場合にのみ同じメンバーを持ちます」これも誤りです。これはセットではなく配列です。したがって、sameMembers([1,1,2],[2,1,2]);falseを返す必要があります。
Redu

1
@Reduは、「同じメンバー」の意味に依存すると思います。つまり、「同じメンバーを持っている」という意味です。私の意見では、sameMembers([1,1,2],[2,1,2])を返す必要がありtrueます。sameMembersInOrder([1,1,2],[2,1,2])AKA deepEquals([1,1,2],[2,1,2])は戻るはずfalseです。
Max Heiber 16

3番目のソリューションarr1.filter...は、arr2にarr1のすべての要素があるかどうかをチェックする場合にのみ機能しますが、その逆も必要です。
Aakash Verma


9

私たちの目的は、基本的に2つの配列が等しいセットかどうかを確認することです。setは数学的に定義されたセットです。最速のソートは、漸近的にO(nlog(n))時間かかります。したがって、配列をソートする場合、少なくともO(nlog(n))時間がかかります。しかし、このタスクをより速く実行できます。これは、辞書データ構造を使用すると、漸近的にO(n)時間(最悪の場合ではなく、平均の場合かかります。JSでは、ディクショナリは単にキーと値を持つオブジェクトです。

/** assumes array elements are primitive types
* check whether 2 arrays are equal sets.
* @param  {} a1 is an array
* @param  {} a2 is an array
*/
function areArraysEqualSets(a1, a2) {
  const superSet = {};
  for (const i of a1) {
    const e = i + typeof i;
    superSet[e] = 1;
  }

  for (const i of a2) {
    const e = i + typeof i;
    if (!superSet[e]) {
      return false;
    }
    superSet[e] = 2;
  }

  for (let e in superSet) {
    if (superSet[e] === 1) {
      return false;
    }
  }

  return true;
}

この関数はプリミティブ型の配列で機能し、配列であると想定a1してa2いることに注意してください。


5

これはどうですか?ES 2017私は:

const array1 = [1, 3, 5];
const array2 = [1, 5, 3];

const isEqual = (array1.length === array2.length) && (array1.every(val => array2.includes(val)));
console.log(isEqual);

1番目の条件は両方の配列の長さが同じかどうかをチェックし、2番目の条件は1番目の配列が2番目の配列のサブセットであるかどうかをチェックします。これら2つの条件を組み合わせると、要素の順序に関係なく、2つの配列のすべての項目が比較されます。

上記のコードは、両方の配列に重複しない項目がある場合にのみ機能します。


3

これら2つの配列を比較すると、内容ではなく配列を表すオブジェクトが比較されます。

2つを比較するには、関数を使用する必要があります。長さが同じであることを確認した後、一方をループし、もう一方と比較する独自のコードを作成できます。


3

ES6を使用した浅い平等のシンプルなソリューション:

const arr1test = arr1.slice().sort()
const arr2test = arr2.slice().sort()
const equal = !arr1test.some((val, idx) => val !== arr2test[idx])

各配列の浅いコピーを作成し、並べ替えます。次に、を使用some()してarr1test値をループし、各値をarr2test同じインデックスの値と照合します。すべての値が等しい場合、をsome()返しfalse、次ににequal評価されtrueます。

を使用することもできますevery()が、配列内のすべての要素を循環してtrue結果を満たすsome()必要がありますが、等しくない値が見つかるとすぐに保釈されます。

const equal = arr1test.every((val, idx) => val === arr2test[idx])

2

ゲームプロジェクトで単純な整数値を使用しました。
各配列の値の数が少なく、元の配列をそのまま使用する必要があったため
、以下を実行しましたが、うまくいきました。(ここに貼り付けるように編集されたコード)

var sourceArray = [1, 2, 3];
var targetArray = [3, 2, 1];

if (sourceArray.length !== targetArray.length) {
    // not equal
    // did something
    return false;
}

var newSortedSourceArray = sourceArray.slice().sort();
var newSortedTargetArray = targetArray.slice().sort();

if (newSortedSourceArray.toString() !== newSortedTargetArray.toString()) { // MAIN CHECK
    // not equal
    // did something
    return false;
}
else {
    // equal
    // did something
    // continued further below
}

// did some more work

return true;

お役に立てば幸いです。


2

ES6の使用

equalsRamda関数を使用しますが、代わりにLodash関数またはUnderscore関数を使用できますisEqual

const R = require('ramda');

const arraysHaveSameValues = (arr1, arr2) => R.equals( [...arr1].sort(), [...arr2].sort() )

スプレッドオペレーターを使用して、元の配列の変更を回避し、関数を純粋な状態に保ちます。


2

reduceループの代わりに使用して賢く見せることもできますが、他の開発者にあなたを賢い人だと思わせるリスクがあります。

function isArrayContentSame(a, b) {
  if (Array.isArray(a) && Array.isArray(b) && a.length == b.length) {
    a = a.concat().sort()
    b = b.concat().sort()
    return a.reduce((acc,e,i) => acc && e === b[i], true)
  } else {
    return false;
  }
}

1

配列内の項目がプリミティブ(数値または単一の文字)の場合、長さの比較とセットの使用を組み合わせて使用​​できます。

function equalArrayItems(arr1, arr2) {
  if (arr1.length !== arr2.length) return false
  const set1 = new Set(arr1)
  const set2 = new Set(arr2)
  const set3 = new Set(arr1, arr2)
  return set1.size === set3.size && set2.size === set3.size
}

1

すでに2020年ですが、他のソリューションのほとんどがソート、O(n * log n)、ライブラリー、またはO(n ^ 2)の複雑さを使用していることに気付きました。

以下は、線形複雑度O(n)の純粋なJavaScriptソリューションです。

/**
 * Check if two arrays of strings or numbers have the same values regardless of the order
 * @param {string[]|number[]} arr1
 * @param {string[]|number[]} arr2
 * @return {boolean}
 */    
compareArrays = (arr1, arr2) => {
    if (arr1.length !== arr2.length) return false;
    const lk1 = {};
    const lk2 = {};
    let i = arr1.length;
    while (--i >= 0) {
        lk1[arr1[i]] = true;
        lk2[arr2[i]] = true
    }
    i = arr1.length;
    while (--i >= 0) {
        const v = arr1[i];
        if (lk1[v] !== lk2[v]) return false;
    }
    return true
}

テスト:

compareArrays([2, 4], [4, 2]) => true
compareArrays([2, 4], [4, 2, 7]) => false
compareArrays([], []) => true

1
ねえ、それは素晴らしいエントリーです!かなり複雑ですが、それは理にかなっています。私は質問があります:私はBig O表記にあまり詳しくありませんが、確かにこのアルゴリズムはO(2n)ですか?ただし、それが大きな違いを生むとは思わないでください。
Carlos Precioso

1
@CarlosPreciosoそのとおりであり、O(2n)= O(n)です。複雑さは一定の係数を
SC1000

0

プロトタイプフレームワークを使用している場合は、配列のintersectメソッドを使用して、それらが同じであることを確認できます(順序に関係なく)。

var array1 = [1,2];
var array2 = [2,1];

if(array1.intersect(array2).length === array1.length) {
    alert("arrays are the same!");
}

これは機能しません[1,2].intersect([1,2,3]).length === [1,2].length-trueを返します。元の配列の長さも比較する必要があります。説明のために投稿を編集しました。
GMA、

実際、私は重複の場合に提案された編集が機能しないことに気づきました...たとえば、それはfalseを返しますarray1 = [1,1,2]; array2 = [1,1,2];...その入力に対して元の回答は失敗しません。
GMA、

あなたは反対のことをすることができます_.difference(array1, array2).length;
Vic

0

親切にこの答えを確認してください

var arr1= [12,18];
var arr2= [12, 18, 20, 11, 19, 14, 6, 7, 8, 16, 9, 3, 1, 13, 5, 4, 15, 10, 2, 17];
for(i=0;i<arr1.length;i++)
{
var array1=arr1[i];
for(j=0;j<arr2.length;j++)
{
    var array2=arr2[j];
    if(array1==array2)
    {
return true;
    }
}
}

2
これは機能的にはこの回答と同等ですが、いくつかのエラーを除きます。まず、これはすべて関数内でラップreturnする必要があります。そうしないと、効果がありません。第二に、あなたは、ソートされた配列を確認するようにすべき[1,2][2,1]同じではないとして検出されます。3番目に重要なことですが、これは実際には一部の要素が同じどうかのみをチェックします。条件はでなければなりませんif (array1!==array2) {return false;}。多分これは将来あなたを助けることができます!
Carlos Precioso、2018年

1
そして追加のコメントとして、コードフローをよりよく理解するためにインデントを使用し、変数名をより明確にしてください。例:array1array2名前を変更することができelem1、およびelem2。これらのヒントは両方とも、将来的に頭痛の種をたくさん救います!
Carlos Precioso、2018年

2
さらに詳しく調べると、なぜ二重ループなのか?両方の配列は同じ長さでなければなりません。そうでない場合、それらは直接等しくありません。この方法では、1つのループしか使用できません。現在、このコードは、最初の配列の要素のいずれかが2番目の配列のどこにあるかどうをチェックします。この回答をチェックして実装方法を確認してください。JavaScriptの旅で頑張ってください!
Carlos Precioso、

0

長い間答えたが、これが簡単な解決策と現代の初心者を探している誰かに役立つことを願っています。

今、私たちのような、この使用して複数のライブラリを達成することができlodashunderscoreなど(これらが原因シンプル、複数の機能と高い用途に、最近のプロジェクトの一部になります)

lodashライブラリの交差点を使用できます。

_.intersection(['2-1', '1'], ['2-2', '3-1', '2-1']); 
// => ['2-1']

これはどのデータ型でも機能します。


0

2つの配列を比較し、両方の配列で同じオブジェクトがあるかどうかを確認する場合は、機能します。例:

Array1 = [a、b、c、d]
Array2 = [d、e、f、g]

ここで、 'd'は両方の配列で共通なので、この関数は真の値を返します。

  cehckArray(array1, array2) {
    for (let i = 0; i < array1.length; i++) {
      for (let j = 0; j < array2.length; j++) {
        if (array1[i] === array2[j]) {
          return true;
        }
      }
    }
    // Return if no common element exist 
    return false;
  }

0

これを試して

function arraysEqual(arr1, arr2){
    if (!Array.isArray(arr1) || !Array.isArray(arr2) || arr1.length!=arr2.length)
        return false;

    return arr1.length==arr1.filter(word => arr2.includes(word)).length;
}

0

受け入れられた答えに基づく別の方法があります。

function compareArrays(array1, array2) {

    if (
        !Array.isArray(array1)
        || !Array.isArray(array2)
        || array1.length !== array2.length
    ) return false;

    var first = array1.sort().map(value => (String(value))).join();
    var second = array2.sort().map(value => (String(value))).join();

    return first == second ? true : false;
}

StackOverflowへようこそ!この回答が機能する場合もありますが、機能しない場合もあります。まず、.sort()が元の配列を変更することに注意してください。今日ではそれは衛生状態が悪いと考えられているので、元の答えが最初に.concat()を実行してコピーを作成します。
Carlos Precioso

そして2番目のポイントは、これが他のJavaScriptと一貫して機能しないことです。{foo: "bar"} === {foo: "bar"}はfalseを返します(これらは別々に作成された2つの異なるオブジェクトです)。そのため、compareArrays([{foo: "bar"}]、[{foo: "bar"}])も一貫性を保つためにfalseを返す必要があります。ただし、オブジェクトの文字列表現が同じであるため、実装ではtrueを返します。それは望ましい振る舞いかもしれませんし、そうでないかもしれませんが、いずれにしても気をつけるべきことです。
Carlos Precioso

0

2つの配列を比較して、両方に同じ要素があるかどうかをチェックする関数。故障しても…

単純な配列に適しています。[文字列、数値、ブール値、null、NaN]。

.sort()は使用しません。元の配列を変更します。悪いと言う人もいます...

注意。この関数は制限されており、Objects [[]、{} "またはこれらの配列内の関数を比較できません。それ自体がObjectである配列です。

   let arraysHasSameElements = (arr1, arr2) => {
        let count =
            // returns counting of occurrences.
            (arr, val) => arr.reduce((count, curr) => (curr === val ? 1 : 0) + count, 0);

        /* this will return true if lengths of the arrays is equal.
           then compare them.*/
        return arr1.length === arr2.length

            // compare arr1 against arr2.
            && arr1.reduce((checks, val) =>

                /*  creating array of checking if a value has equal amount of occurrences
                    in both arrays, then adds true 'check'. */
                checks.concat(count(arr1, val) === count(arr2, val)), [])

                // checking if each check is equal to true, then .every() returns true.
                .every(check => check);
    }

    let arr1 = ['',-99,true,NaN,21,null,false,'help',-99,'help',NaN], 
        arr2 = [null,-99,'',NaN,NaN,false,true,-99,'help',21,'help'];
    arraysHasSameElements(arr1, arr2); //true

    let arr3 = [false,false,false,false,false,false], 
        arr4 = [false,false,false,false,false,false]
    arraysHasSameElements(arr3, arr4); //true


    // here we have uncommented version.
    let arraysHasSameElements = (arr1, arr2) => {
        let count = (arr, val) => arr.reduce((count, curr) => (curr === val ? 1:0) + count, 0);
        return arr1.length === arr2.length && arr1.reduce((checks, val) =>
            checks.concat(count(arr1, val) === count(arr2, val)), []).every(check => check);
    }

-1

2つの配列を比較する簡単なソリューション:

var array1 = [2, 4];
var array2 = [4, 2];

array1.sort();
array2.sort();

if (array1[0] == array2[0]) {
    console.log("Success");
}else{
    console.log("Wrong");
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.