Oczekuj, że tablice będą równe, ignorując kolejność

86

Czy z Jasmine można sprawdzić, czy dwie tablice zawierają te same elementy, ale niekoniecznie są w tej samej kolejności? to znaczy

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

expect(array1).toEqualIgnoreOrder(array2);//should be true
David mówi, że przywróć Monikę
źródło
23
expect(array1.sort()).toEqual(array2.sort());?
raina77ow
@ raina77ow Myślę, że to również zadziała.
David mówi Przywróć Monikę
1
Powinienem uczynić to odpowiedzią?
raina77ow
1
@ raina77ow Robi się trochę bardziej skomplikowane, gdy jest to tablica obiektów. Byłoby miło, gdyby Jasmine miała do tego coś po wyjęciu z pudełka.
David mówi Przywróć Monikę
2
Nie znalazłem nic wspaniałego w samym jaśminie, więc faktycznie wprowadziłem lodash (lub możesz użyć podkreślenia / innej biblioteki kolekcji js) do mojego projektu testowego dla takich rzeczy.
ktharsis

Odpowiedzi:

61

Jeśli są to tylko liczby całkowite lub inne prymitywne wartości, możesz sort()je przed porównaniem.

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

Jeśli są to obiekty, połącz je z map()funkcją, aby wyodrębnić identyfikator, który będzie porównywany

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());
Kolorowa Panda
źródło
domyślna metoda sortowania tablic używa porównania ciągów dla liczb. "10" < "2" === true
Shmiddty
[10, 2, 1].sort() ---> [1, 10, 2]
Shmiddty
7
@Shmiddty Nie rozumiem, jakie to ma znaczenie w tym przypadku. Dopóki kolejność jest taka sama dla obu tablic, powinno być w porządku.
Kolorowa Panda
1
Słuszna uwaga. Warto jednak zauważyć, że sortdzieje się to na miejscu. (mutuje instancję, w której jest nazywana)
Shmiddty
1
Część dotycząca obiektu tej odpowiedzi w rzeczywistości nie zweryfikuje, czy obiekty pasują do siebie, ponieważ porównuje tylko odwzorowane tablice. Nie potrzebujesz mapy, sortprzyjmuje opcjonalną funkcję, której może użyć do porównania.
slifty
19

jaśmin w wersji 2.8 i późniejszych

jasmine.arrayWithExactContents()

Który oczekuje, że tablica zawiera dokładnie wymienione elementy w dowolnej kolejności.

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

Zobacz https://jasmine.github.io/api/3.4/jasmine.html

keksmasta
źródło
13

prosty...

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

expect(array1).toEqual(jasmine.arrayContaining(array2));
ProfiProg
źródło
7
Niezła odpowiedź! Musisz również sprawdzić, czy długości są równe, w przeciwnym razie uzyskasz fałszywie dodatni wynik na [1,2,3,4] i [3,2,1].
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)
Jannic Beck
źródło
2
Użyj .forEachzamiast, .mapaby zaoszczędzić trochę czasu i sporo pamięci.
Darkhogg
1
Niestety to minie z następujących tablic mimo że są różne: array1 = [1, 2],array2 = [1, 1]
redbmk
2
Niezły chwyt @redbmk Dodałem na to czek, dzięki!
Jannic Beck
Myślę, że nadal występuje problem - a co jeśli tablice są [1,1,2]i [1,2,2]? Może używając mapy dla każdego z nich lub czegoś? np. array1.reduce((map, item) => { map.set(item, (map.get(item) || 0) + 1)), new Map())dla obu tablic, a następnie przejrzyj je i sprawdź, czy kwoty są takie same? Wydaje się, że jest to wiele iteracji, ale byłoby dokładniejsze.
redbmk
Można użyć wyjątków z tablicy kontrolnej (usunąć element, gdy zostanie znaleziony, a następnie sprawdzić, czy na końcu długość wynosi 0), ale w zwykłych przypadkach nie jest to warte wysiłku.
lifecoder
4

Możesz użyć Expect.arrayContaining (array) ze standardowego jest:

  const expected = ['Alice', 'Bob'];
  it('matches even if received contains additional elements', () => {
    expect(['Alice', 'Bob', 'Eve']).toEqual(expect.arrayContaining(expected));
  });
przystań
źródło
2

Pakiet jest-extended dostarcza nam kilku asercji, aby uprościć nasze testy, jest mniej szczegółowy, a dla testów zakończonych niepowodzeniem błąd jest bardziej wyraźny.

W tym przypadku możemy użyć toIncludeSameMembers

expect([{foo: "bar"}, {baz: "qux"}]).toIncludeSameMembers([{baz: "qux"}, {foo: "bar"}]);
dave008
źródło
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;
}
Ravi
źródło
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
    })
}

Pomysł polega na tym, aby najpierw ustalić, czy długość dwóch tablic jest taka sama, a następnie sprawdzić, czy wszystkie elementy znajdują się w tablicy drugiej.

SkuraZZ
źródło
Nie uwzględnia częstotliwości pozycji: equal([1, 1, 2], [1, 2, 2])zwrotów true.
MarkMYoung
0

Oto rozwiązanie, które będzie działać dla dowolnej liczby lub tablic

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)),
    );

Niektóre testy (kilka odpowiedzi na to pytanie nie uwzględnia tablic z wieloma elementami o tej samej wartości, więc [1, 2, 2] i [1, 2] zwróciłyby nieprawidłowo prawdę)

[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
Tyler
źródło
0

Ten algorytm doskonale sprawdza się w przypadku tablic, w których każdy element jest unikalny. Jeśli nie, możesz coś dodać, aby sprawdzić, czy nie ma duplikatów ...

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;
}

Joe DF
źródło
0

To podejście ma gorszą teoretyczną wydajność w najgorszym przypadku w czasie wykonywania, ale ponieważ nie wykonuje żadnych zapisów w tablicy, może być szybsze w wielu okolicznościach (jeszcze nie przetestowano wydajności):

OSTRZEŻENIE: Jak zauważył Torben w komentarzach, to podejście działa tylko wtedy, gdy obie tablice mają unikalne (nie powtarzające się) elementy (tak jak kilka innych odpowiedzi tutaj).

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

Domi
źródło
1
Co masz na myśli, mówiąc, że tworzy on wiele kopii? Array#sortsortuje tablice w miejscu.
philraj
1
Niepowodzenia dla tych tablic: [1,1,2,3], [3,3,1,2].
Torben Kohlmeier
1
@TorbenKohlmeier Dzięki, zaktualizowałem moją odpowiedź (przyznając się do porażki w odniesieniu do nieunikalnych tablic)
Domi
0

Obecnie istnieje odpowiednik dla tego PRZYPADKU UŻYCIA:

https://github.com/jest-community/jest-extended/pull/122/files

test('passes when arrays match in a different order', () => {
  expect([1, 2, 3]).toMatchArray([3, 1, 2]);
  expect([{ foo: 'bar' }, { baz: 'qux' }]).toMatchArray([{ baz: 'qux' }, { foo: 'bar' }]);
});
Daniel Maldonado
źródło
-1

Możesz użyć czegoś takiego:

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

Pamiętaj o imporcie jasmine. Lub dodaj go do swojego.eslintrc

KViin Coyoy
źródło
-3

Jest ma funkcję o nazwie, expect.arrayContainingktóra zrobi dokładnie to, co chcesz:

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

możesz chcieć sprawdzić, czy mają tę samą długość, ponieważ test przejdzie, jeśli

oczekiwana tablica jest podzbiorem otrzymanej tablicy

według doc.

EDYCJA: Przepraszam, że nie zauważyłem tagu jaśminu, to jest sposób, w jaki działa z Jest

David Lee
źródło