Dizilerin sıralamayı göz ardı ederek eşit olmasını bekleyin


93

Jasmine ile, 2 dizinin aynı öğeleri içerip içermediğini test etmenin bir yolu var, ancak aynı sırada olması gerekmez mi? yani

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

expect(array1).toEqualIgnoreOrder(array2);//should be true

24
expect(array1.sort()).toEqual(array2.sort());?
raina77ow

@ raina77ow Ben de işe yarayacağını tahmin ediyorum.
David,

1
Bunu bir cevap yapmalı mıyım?
raina77ow

1
@ raina77ow Bir dizi nesne olduğunda biraz daha karmaşık hale gelir. Jasmine'in bunun için kutudan çıkardığı bir şey olması güzel olurdu.
David,

2
Yasemin'in kendisinde harika bir şey bulamadım, bu yüzden aslında bunun gibi şeyler için test projeme lodash'ı (veya alt çizgi / diğer js koleksiyon kitaplığını kullanabilirsiniz) ekledim.
ktharsis

Yanıtlar:


65

Yalnızca tamsayılar veya diğer ilkel değerlerden ibaretse, sort()karşılaştırmadan önce bunları yapabilirsiniz .

expect(array1.sort()).toEqual(array2.sort());

Nesneleri varsa, map()karşılaştırılacak bir tanımlayıcı çıkarmak için onu işlevle birleştirin

array1 = [{id:1}, {id:2}, {id:3}];
array2 = [{id:3}, {id:2}, {id:1}];

expect(array1.map(a => a.id).sort()).toEqual(array2.map(a => a.id).sort());

varsayılan dizi sıralama yöntemi sayılar için dize karşılaştırması kullanır. "10" < "2" === true
Shmiddty

[10, 2, 1].sort() ---> [1, 10, 2]
Shmiddty

9
@Shmiddty Bu durumda ne kadar önemli olduğunu anlamıyorum. Sıra her iki dizi için de aynı olduğu sürece, iyi olmalıdır.
Renkli Panda

1
Doğru tespit. Yine de bunun sortyerinde gerçekleştiğini belirtmekte fayda var . (çağrıldığı örneği değiştirir)
Shmiddty

1
Bu cevabın nesne kısmı, yalnızca eşlenen dizileri karşılaştırdığı için nesnelerin eşleştiğini doğrulamayacaktır. Haritaya ihtiyacınız sortyoktur, karşılaştırma yapmak için kullanabileceği isteğe bağlı bir işlevi alır.
slifty

22

yasemin 2.8 ve sonraki sürümlerde

jasmine.arrayWithExactContents()

Bu, bir dizinin tam olarak listelenen öğeleri herhangi bir sırada içermesini bekler.

array1 = [1,2,3];
array2 = [3,2,1];
expect(array1).toEqual(jasmine.arrayWithExactContents(array2))

Bkz. Https://jasmine.github.io/api/3.4/jasmine.html


13

basit...

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

expect(array1).toEqual(jasmine.arrayContaining(array2));

7
Güzel cevap! Uzunlukların eşit olup olmadığını da kontrol etmeniz gerekir, aksi takdirde [1,2,3,4] ve [3,2,1] 'de yanlış pozitif olursunuz.
Kristian Hanekamp

10
// check if every element of array2 is element of array1
// to ensure [1, 1] !== [1, 2]
array2.forEach(x => expect(array1).toContain(x))

// check if every element of array1 is element of array2
// to ensure [1, 2] !== [1, 1]
array1.forEach(x => expect(array2).toContain(x))

// check if they have equal length to ensure [1] !== [1, 1]
expect(array1.length).toBe(array2.length)

2
Biraz zamandan ve bir sürü bellekten tasarruf etmek için .forEachyerine kullanın .map.
Darkhogg

1
Ne yazık ki bu farklı olsa bile aşağıdaki diziler ile geçecek: array1 = [1, 2],array2 = [1, 1]
redbmk

2
Güzel yakala @redbmk Bunun için bir çek ekledim, teşekkürler!
Jannic Beck

Sanırım hala bir sorun var - ya diziler [1,1,2]ve ise [1,2,2]? Belki her biri için bir Harita veya başka bir şey kullanmak? örneğin array1.reduce((map, item) => { map.set(item, (map.get(item) || 0) + 1)), new Map()), her iki dizi için, sonra bunların arasında döngü yapın ve miktarların aynı olup olmadığını kontrol edin. Çok fazla yineleme gibi görünüyor, ancak daha kapsamlı olacaktır.
redbmk

Kontrol dizisinden istisnalar kullanılabilir (bulunduğunda elemanı kaldırın, sonra uzunluğun sonunda 0 olup olmadığını kontrol edin), ancak normal durumlarda bu çabaya değmez.
lifecoder

10

Standart jest'den beklenen.arrayContaining (dizi) işlevini kullanabilirsiniz:

  const expected = ['Alice', 'Bob'];
  it('matches even if received contains additional elements', () => {
    expect(['Alice', 'Bob', 'Eve']).toEqual(expect.arrayContaining(expected));
  });

Mükemmel çözüm! Bu seçilen cevap olmalıdır ..
rohit_wason

2

Jest-genişletilmiş paket daha az ayrıntılı var ve testler başarısız olduğu için hata daha açık, bizim testleri basitleştirmek için bize birkaç iddialarını sağlar.

Bu durum için toIncludeSameMembers kullanabiliriz

expect([{foo: "bar"}, {baz: "qux"}]).toIncludeSameMembers([{baz: "qux"}, {foo: "bar"}]);

1
//Compare arrays without order
//Example
//a1 = [1, 2, 3, 4, 5]
//a2 = [3, 2, 1, 5, 4]
//isEqual(a1, a2) -> true
//a1 = [1, 2, 3, 4, 5];
//a2 = [3, 2, 1, 5, 4, 6];
//isEqual(a1, a2) -> false


function isInArray(a, e) {
  for ( var i = a.length; i--; ) {
    if ( a[i] === e ) return true;
  }
  return false;
}

function isEqArrays(a1, a2) {
  if ( a1.length !== a2.length ) {
    return false;
  }
  for ( var i = a1.length; i--; ) {
    if ( !isInArray( a2, a1[i] ) ) {
      return false;
    }
  }
  return true;
}

0
function equal(arr1, arr2){
    return arr1.length === arr2.length
    &&
    arr1.every((item)=>{
        return arr2.indexOf(item) >-1
    }) 
    &&
    arr2.every((item)=>{
        return arr1.indexOf(item) >-1
    })
}

Buradaki fikir, önce iki dizinin uzunluğunun aynı olup olmadığını belirlemek, ardından tüm öğelerin diğerinin dizisinde olup olmadığını kontrol etmektir.


Bu, öğelerin sıklığını hesaba katmaz: equal([1, 1, 2], [1, 2, 2])iadeler true.
MarkMYoung

0

İşte herhangi bir sayı veya dizi için işe yarayacak bir çözüm

https://gist.github.com/tvler/cc5b2a3f01543e1658b25ca567c078e4

const areUnsortedArraysEqual = (...arrs) =>
  arrs.every((arr, i, [first]) => !i || arr.length === first.length) &&
  arrs
    .map(arr =>
      arr.reduce(
        (map, item) => map.set(item, (map.get(item) || 0) + 1),
        new Map(),
      ),
    )
    .every(
      (map, i, [first]) =>
        !i ||
        [...first, ...map].every(([item]) => first.get(item) === map.get(item)),
    );

Bazı testler (bu soruya verilen birkaç cevap aynı değere sahip birden çok öğeye sahip dizileri hesaba katmaz, bu nedenle [1, 2, 2] ve [1, 2] yanlış bir şekilde doğru döndürür)

[1, 2] true
[1, 2], [1, 2] true
[1, 2], [1, 2], [1, 2] true
[1, 2], [2, 1] true
[1, 1, 2], [1, 2, 1] true
[1, 2], [1, 2, 3] false
[1, 2, 3, 4], [1, 2, 3], [1, 2] false
[1, 2, 2], [1, 2] false
[1, 1, 2], [1, 2, 2] false
[1, 2, 3], [1, 2], [1, 2, 3] false

0

Bu algoritma, her öğenin benzersiz olduğu diziler için harikadır. Değilse, kopyaları kontrol etmek için bir şeyler ekleyebilirsiniz ...

tests = [
  [ [1,0,1] , [0,1,1] ],
  [ [1,0,1] , [0,0,1] ], //breaks on this one...
  [ [2,3,3] , [2,2,3] ], //breaks on this one also...
  [ [1,2,3] , [2,1,3] ],
  [ [2,3,1] , [1,2,2] ],
  [ [2,2,1] , [1,3,2] ]
]

tests.forEach(function(test) {
  console.log('eqArraySets( '+test[0]+' , '+test[1]+' ) = '+eqArraySets( test[0] , test[1] ));
});


function eqArraySets(a, b) {
	if ( a.length !== b.length ) { return false; }
	for ( var i = a.length; i--; ) {
		if ( !(b.indexOf(a[i])>-1) ) { return false; }
		if ( !(a.indexOf(b[i])>-1) ) { return false; }
	}
	return true;
}


0

Bu yaklaşım daha kötü teorik en kötü durum çalışma zamanı performansına sahiptir, ancak dizi üzerinde herhangi bir yazma yapmadığı için birçok durumda daha hızlı olabilir (performansı henüz test etmemiş):

UYARI: Torben'in yorumlarda belirttiği gibi, bu yaklaşım yalnızca her iki dizinin de benzersiz (tekrar etmeyen) öğeleri varsa işe yarar (tıpkı buradaki diğer yanıtların birçoğu gibi).

/**
 * Determine whether two arrays contain exactly the same elements, independent of order.
 * @see /programming/32103252/expect-arrays-to-be-equal-ignoring-order/48973444#48973444
 */
function cmpIgnoreOrder(a, b) {
  const { every, includes } = _;
  return a.length === b.length && every(a, v => includes(b, v));
}

// the following should be all true!
const results = [
  !!cmpIgnoreOrder([1,2,3], [3,1,2]),
  !!cmpIgnoreOrder([4,1,2,3], [3,4,1,2]),
  !!cmpIgnoreOrder([], []),
  !cmpIgnoreOrder([1,2,3], [3,4,1,2]),
  !cmpIgnoreOrder([1], []),
  !cmpIgnoreOrder([1, 3, 4], [3,4,5])
];

console.log('Results: ', results)
console.assert(_.reduce(results, (a, b) => a && b, true), 'Test did not pass!');
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.5/lodash.js"></script>


1
Çok sayıda kopya oluşturduğunu söylediğinizde ne demek istiyorsunuz? Array#sortdizileri yerinde sıralar.
philraj

1
Şu diziler için başarısız: [1,1,2,3], [3,3,1,2].
Torben Kohlmeier

1
@TorbenKohlmeier Teşekkürler, cevabımı güncelledim (benzersiz olmayan dizilerle ilgili yenilgiyi kabul ederek)
Domi


-1

Şunun gibi bir şey kullanabilirsiniz:

expect(array1).toEqual(jasmine.arrayContaining(array2));

İçe aktarmayı unutmayın jasmine. Ya da.eslintrc


-4

Jest'in expect.arrayContainingtam olarak istediğinizi yapacak bir işlevi vardır :

expect(array1).toEqual(expect.arrayContaining(array2))

Testin geçip geçmeyeceğinden aynı uzunlukta olup olmadıklarını da kontrol etmek isteyebilirsiniz.

beklenen dizi, alınan dizinin bir alt kümesidir

doktora göre.

DÜZENLEME: Yasemin etiketini fark etmediğim için üzgünüm, bu Jest ile çalışmanın bir yolu

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.