Dizileri karşılaştırmak için lodash kullanma (sırasız öğeler varlığı)


126

Bunu döngüler kullanarak yapabileceğimi biliyorum, ancak bunu yapmanın zarif bir yolunu bulmaya çalışıyorum:

İki dizim var:

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

lodashYukarıdaki iki dizinin aynı olduğunu doğrulamak için kullanmak istiyorum . 'Aynı' derken hiçbir öğe olduğu anlamına array1içerdiği olmadığını array2.

Bu öğeler arasındaki eşitliği kontrol etmek açısından:

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

veya

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

Harfler her zaman sırayla olacağından ikisi de çalışır.

Yanıtlar:


224

Dış diziyi sıralarsanız, _.isEqual()iç dizi zaten sıralandığı için kullanabilirsiniz.

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

.sort()Bunun dizileri değiştireceğini unutmayın . Bu sizin için bir sorunsa, önce (örneğin) .slice()veya yayma operatörünü ( ...) kullanarak bir kopya oluşturun .

Veya aşağıdaki yorumda Daniel Budick'in önerdiği şekilde yapın:

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

Lodash sortBy()diziyi değiştirmeyecek.


6
Array.sort () 'un orijinal diziyi değiştirdiğini göz önünde bulundurun. Belki bu daha iyi olabilir: var dizi1 = [['a', 'b'], ['b', 'c']]; var dizi2 = [['b', 'c'], ['a', 'b']]; _.isEqual ([... dizi1] .sort (), [... dizi2] .sort ()); // true
Yaniv Efraim

3
.sort()Kullanıcı için bir sorunsa önce kopyalama için seçenekler öneren ve değişime uğradığını belirten iki cümle eklendi .
Trott

6
Zaten Lodash kullanıyorsanız, _.isEqual(_.sortBy(array1), _sortBy(array2))mutasyonu önlemek için yapabilirsiniz .
Daniel Budick

1
@DanielBudick Teşekkürler! Bunu cevaba ekledim. Harika bir öneri.
Trott

33

Sen lodashs kullanabilirsiniz xorbunun için

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

[1, 1] dizisinin [1] dizisinden farklı olduğunu düşünürseniz, performansı şu şekilde biraz artırabilirsiniz:

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

1
Dizilerin yine de sıralanması gerekiyor.
Sovattha Sok

1
Bu, yeni sürüm için daha iyi bir yol olmalı
Leonardo

@Sovattha Sok Dizilerin sıralanmasına gerek yok. Yapmak _.xor([3,4], [4,3]).length == 0seni gerçek yapacak.
Nikolay

1
Bir uyarı: Bu teknik, "küçük" diziler için iyi çalışır, ancak dizileriniz çok büyükse ve çoğunlukla farklıysa, bir performans ve bellek açısından zahmetli olabilir, çünkü _.xor () ilk farkı geçmeye devam edecektir. Diğer bir deyişle, tespit edilen ilk farkta hızlı geri dönmez.
XDS

6

'Aynı' derken, dizi1'de dizi2'de yer almayan hiçbir öğe olmadığını kastediyorum.

Öğeler varsa umursamıyorsun eğer iyi çalışır bunun için () ve farkı (), düzleştirmek kullanabilirsiniz değildir de . Diye soruyorsan gibi geliyor dizi2 bir alt kümesi dizi1 olduğunu ?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

Burada zaten cevaplar var, ancak işte benim saf JS uygulamam. En uygun olup olmadığından emin değilim, ama kesinlikle şeffaf, okunabilir ve basit.

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

Buradaki mantık, contains()öğesinin atüm öğelerini içeriyorsa b, onları aynı sete koymanın boyutu değiştirmeyeceğidir.

Örneğin, eğer const a = [1,2,3,4]ve const b = [1,2]sonra new Set([...a, ...b]) === {1,2,3,4}. Gördüğünüz gibi, ortaya çıkan küme ile aynı unsurlara sahip a.

Oradan, daha özlü hale getirmek için, onu şu şekilde özetleyebiliriz:

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

1

PURE JS (diziler ve alt diziler rastgele sırayla 2'den fazla öğe içerdiğinde de çalışır). Dizeler, dizelerde ,kullanılmayan join('-')parametre karakteri olarak kullanım içeriyorsa (utf olabilir)

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


0

Bir _.differencefark olup olmadığını görmek için fonksiyonu kullanabiliriz .

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

Umarım bu sana yardımcı olmuştur.


5
Yanlış, senin işlevi alacak trueiçinconsole.log(isSame([1,2], [2,3,1]));
David Lin

3
Bunu belirtmek için @DavidLin'e teşekkür ederim. Bu davayı dikkate almak için değişiklikleri yaptım. Teşekkürler ve rahatsızlıktan dolayı özür dilerim.
Amitesh

2
uzunluklar aynı değilse, a & b için yer değiştirmenize gerek yoktur. Uzunluklar farklıysa zaten aynı olamazlar, bu nedenle (arrayOne.lenght! == arrayTwo.lenght) false döndürür;
Alex

1
-1 Bunlara ave bdeğişkenlere sahip olmanın anlamı yok . Sen sadece içeride bu değişkenleri kullanmak if-thenparçası ve ilk yaptığın şey şu tek satır tam olarak aynı işe yarayacak hattı 2. yüklenen bu değerleri vardır atmak edilir: return arrayOne.length <= arrayTwo.length && _.isEmpty(_.difference(arrayTwo.sort(), arrayTwo.sort());. Ve <=ayrıca geliştirilebilir ===.
Mariano Desanze

1
Ve _.difference1. bağımsız değişkenin eksik öğelerini döndürür, ancak 2. bağımsız değişkendeki eksik öğeleri döndürmez. Bu yüzden yanlış dönecektir true2 seçtikleri içinde 1 öğeleri tekrarlamak zaman: isSame([1, 2, 3], [1, 2, 2]).
Mariano Desanze

0

Düzenleme: Bu sorunun çok boyutlu yönünü kaçırdım, bu yüzden insanların tek boyutlu dizileri karşılaştırmasına yardımcı olma ihtimaline karşı bunu burada bırakıyorum

Bu eski bir soru, ancak .sort()veya kullanma hızıyla ilgili sorunlar yaşıyordum sortBy(), bu yüzden bunun yerine şunu kullandım:

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

Hızlı başarısız olması amaçlanmıştı ve benim amaçlarım için iyi çalışıyor.


Son kontrol gerçekten gerekli mi? array1.every((str) => array2.includes(str))yeterli olmalı. Ayrıca OP, lodash'ı kullanmak istedi, en azından neden bir vanillaJS çözümü önerdiğinizi söylemelisiniz (... şimdi her şeye sahibiz ve içeriyor ...). Lütfen fonksiyonunuzu sağlanan probleme nasıl uygulayacağınıza dair bir örnek verin (2 boyutlu diziler).
satır-o

Bu iyi bir nokta - bunun çok boyutlu yönüne değinmedim, lodash gerekliliğine değil. lodash methods to compare arrays without considering orderModern Javascript'te bir alternatifi arayan herkesin (benim yaptığım gibi) faydalı olacağını düşündüm . arraysContainSameStrings(['1', '2', '2'], ['1', '2', '3'])Aksi takdirde true döneceği için ikinci kontrol gereklidir .
Yardımcı
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.