lodashを使用して配列を比較する(アイテムは順序なしで存在)


124

私はループを使用してそれを行うことができることを知っていますが、これを行うエレガントな方法を見つけようとしています:

2つの配列があります。

var array1 = [['a', 'b'], ['b', 'c']];
var array2 = [['b', 'c'], ['a', 'b']];

lodash上記の2つの配列が同じであることを確認するために使用します。「同じ」とは、にarray1含まれていないアイテムがないことを意味しarray2ます。

これらのアイテム間の同等性をチェックすることに関して:

['a', 'b'] == ['b', 'a'] 

または

['a', 'b'] == ['a', 'b'] 

文字は常に正しいので、どちらも機能します。

回答:


224

外側の配列を並べ替えると、_.isEqual()内側の配列が既に並べ替えられているので使用できます。

var array1 = [['a', 'b'], ['b', 'c']];
var array2 = [['b', 'c'], ['a', 'b']];
_.isEqual(array1.sort(), array2.sort()); //true

.sort()配列が変更されることに注意してください。それが問題である場合は、まず(たとえば).slice()またはスプレッド演算子(...)を使用してコピーを作成します。

または、以下のコメントでDaniel Budickが推奨するようにしてください。

_.isEqual(_.sortBy(array1), _.sortBy(array2))

Lodash sortBy()は配列を変更しません。


6
array.sort()が元の配列を変更していることを考慮してください。多分これはもっと良いかもしれません:var array1 = [['a'、 'b']、['b'、 'c']]; var array2 = [['b'、 'c']、['a'、 'b']]; _.isEqual([... array1] .sort()、[... array2] .sort()); // true
Yaniv Efraim 2017年

3
.sort()変異していることを指摘し、ユーザーの問題である場合は最初にコピーするオプションを提案する2つの文を追加しました。
Trott 2017年

6
すでにlodashを使用している場合は_.isEqual(_.sortBy(array1), _sortBy(array2))、変異を防ぐためだけに使用できます。
ダニエル・ブディック

1
@DanielBudickありがとう!私はそれを答えに加えました。素晴らしい提案。
Trott、

32

xorこれにはロダッシュを使用できます

doArraysContainSameElements = _.xor(arr1, arr2).length === 0

配列[1、1]を配列[1]とは異なるものと見なす場合は、パフォーマンスを少し向上させることができます。

doArraysContainSameElements = arr1.length === arr2.length === 0 && _.xor(arr1, arr2).length === 0

1
配列はとにかくソートする必要があります。
Sovattha Sok

1
これは新しいバージョンのより良い方法になるはずです
Leonardo

@Sovattha Sok配列をソートする必要はありません。そう_.xor([3,4], [4,3]).length == 0することであなたは真実になります
ニコライ

1
注意:この手法は「小さな」配列に適していますが、配列が大きく、ほとんどが異なる場合、_。xor()が最初の違いを超えて継続するため、パフォーマンスとメモリの面で苦痛になる可能性があります。言い換えると、最初に検出された差異では速く戻りません。
XDS

6

「同じ」とは、array2に含まれていない配列がarray1にないことを意味します。

内の項目がある場合は、あなたが気にしない場合は、うまく機能し、このため()との違いを()、平坦化使用することができませんでは。あなたが求めているように聞こえる配列2のサブセットARRAY1ありますかarray2array1

var array1 = [['a', 'b'], ['b', 'c']];
var array2 = [['b', 'c'], ['a', 'b']];

function isSubset(source, target) {
    return !_.difference(_.flatten(source), _.flatten(target)).length;
}

isSubset(array1, array2); // → true
array1.push('d');
isSubset(array1, array2); // → false
isSubset(array2, array1); // → true

4

ここにはすでに答えがありますが、これが私の純粋なJS実装です。最適かどうかはわかりませんが、透明で読みやすく、シンプルです。

// Does array a contain elements of array b?
const contains = (a, b) => new Set([...a, ...b]).size === a.length
const isEqualSet = (a, b) => contains(a, b) && contains(b, a)

で根拠contains()場合、つまりa、すべての要素が含まれませんb、それらを同じセットに入れてもサイズは変更されないということです。

たとえば、const a = [1,2,3,4]そしてconst b = [1,2]、その後、new Set([...a, ...b]) === {1,2,3,4}。ご覧のとおり、結果のセットは次の要素と同じです。aます。

そこから、より簡潔にするために、次のように要約できます。

const isEqualSet = (a, b) => {
  const unionSize = new Set([...a, ...b])
  return unionSize === a.length && unionSize === b.length
}

1

PURE JS(配列およびサブ配列に任意の順序で2つ以上の要素がある場合にも機能します)。文字列に文字列で,使用されていないjoin('-')パラメータ文字(utfの可能性があります)としての使用が含まれている場合

array1.map(x=>x.sort()).sort().join() === array2.map(x=>x.sort()).sort().join()


0

_.difference関数を使用して、違いがあるかどうかを確認できます。

function isSame(arrayOne, arrayTwo) {
   var a = _.unique(arrayOne),
       b = _.unique(arrayTwo);

   if (a.length <= b.length) {
      a = arrayTwo;
      b = arrayOne;
      return _.isEmpty(_.difference(a.sort(), b.sort()));
   } else {
      return false;
   }

}

// examples
console.log(isSame([1, 2, 3], [1, 2, 3])); // true
console.log(isSame([1, 2, 4], [1, 2, 3])); // false
console.log(isSame([1, 2], [2, 3, 1])); // false
console.log(isSame([2, 3, 1], [1, 2])); // false

// Test cases pointed by Mariano Desanze, Thanks.
console.log(isSame([1, 2, 3], [1, 2, 2])); // false
console.log(isSame([1, 2, 2], [1, 2, 2])); // true
console.log(isSame([1, 2, 2], [1, 2, 3])); // false

これがお役に立てば幸いです。


5
間違った、あなたの関数が取得するtrueためにconsole.log(isSame([1,2], [2,3,1]));
デビッド・リン

3
@DavidLinに指摘していただきありがとうございます。その場合を考慮して変更を加えました。ご不便をおかけして申し訳ありません。
アミテッシュ2017年

2
長さが同じでない場合は、aとbを入れ替える必要はありません。長さが異なる場合、それらをすでに同じにすることはできません。したがって、if(arrayOne.lenght!== arrayTwo.lenght)はfalseを返します。
アレックス

1
-1それらab変数があることに意味はありません。あなたは唯一の内部でこれらの変数を使用するif-then部分、そしてあなたが最初の事は、私は以下の1行がまったく同じに動作するとは思わライン2でロードされ、それらの値が破棄されていますreturn arrayOne.length <= arrayTwo.length && _.isEmpty(_.difference(arrayTwo.sort(), arrayTwo.sort());。また、<=をに改善することもでき===ます。
マリアーノデサンツェ

1
また_.difference、1番目の引数の欠落しているアイテムを返しますが、2番目の欠落しているアイテムは返しません。そのためtrue、1日2日にアイテムを繰り返すと、これは誤って返されますisSame([1, 2, 3], [1, 2, 2])
マリアーノデサンツェ

0

編集:私はこの質問の多次元の側面を逃したので、1次元配列を比較するのに役立つ場合に備えて、ここではこれを残します

古い質問ですが、.sort()またはの使用速度に問題があったsortBy()ため、代わりにこれを使用しました。

function arraysContainSameStrings(array1: string[], array2: string[]): boolean {
  return (
    array1.length === array2.length &&
    array1.every((str) => array2.includes(str)) &&
    array2.every((str) => array1.includes(str))
  )
}

それは速く失敗するように意図されていて、私の目的のためにうまく働きます。


最後のチェックは本当に必要ですか? array1.every((str) => array2.includes(str))十分なはずです。また、OPはlodashを使用したかったので、少なくともvanillaJSソリューションを提案する理由を少なくとも言う必要があります(... 提供された問題(2次元配列)に関数を適用する方法の例も提供してください。
line-o

それは良い点です-私はそれの多次元の側面に取り組みませんでした。lodashの要件ではありません。(私がしたように)検索している人なら誰でもlodash methods to compare arrays without considering order、現代のJavascriptで別の方法を探すのは便利だと思いました。arraysContainSameStrings(['1', '2', '2'], ['1', '2', '3'])それ以外の場合はtrueを返すため、2番目のチェックが必要です。お役に立てればと思いますので、ここに置いておきますが、質問に答えられなかったことに感謝します
charliematters
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.