Chciałbym porównać dwie tablice ... idealnie, efektywnie. Nic szczególnego, tylko true
jeśli są identyczne, a false
jeśli nie. Nic dziwnego, że operator porównania nie działa.
var a1 = [1,2,3];
var a2 = [1,2,3];
console.log(a1==a2); // Returns false
console.log(JSON.stringify(a1)==JSON.stringify(a2)); // Returns true
JSON koduje każdą tablicę, ale czy istnieje szybszy lub „lepszy” sposób na proste porównywanie tablic bez konieczności iterowania każdej wartości?
javascript
arrays
json
Julian H. Lam
źródło
źródło
([] == []) == false
.Odpowiedzi:
Aby porównać tablice, przejrzyj je i porównaj każdą wartość:
Porównywanie tablic:
Stosowanie:
Możesz powiedzieć „ Ale porównywanie ciągów jest znacznie szybsze - bez pętli ... ”, więc powinieneś zauważyć, że istnieją pętle ARE. Pierwsza pętla rekurencyjna, która konwertuje Array na łańcuch, a druga, która porównuje dwa łańcuchy. Tak więc ta metoda jest szybsza niż użycie ciągu .
Uważam, że większe ilości danych powinny zawsze być przechowywane w tablicach, a nie w obiektach. Jeśli jednak używasz obiektów, można je również częściowo porównać.
Oto jak:
Porównywanie obiektów:
Powiedziałem powyżej, że dwa wystąpienia obiektów nigdy nie będą równe, nawet jeśli w tej chwili zawierają te same dane:
Ma to powód, ponieważ w obiektach mogą znajdować się na przykład zmienne prywatne.
Jeśli jednak użyjesz struktury obiektu do przechowywania danych, porównanie jest nadal możliwe:
Pamiętaj jednak, że ten ma służyć do porównywania danych podobnych do JSON, a nie instancji klas i innych rzeczy. Jeśli chcesz porównać bardziej skomplikowane obiekty, spójrz na tę odpowiedź i jej bardzo długą funkcję .
Aby to działało
Array.equals
, musisz nieco zmodyfikować oryginalną funkcję:Zrobiłem małe narzędzie testowe dla obu funkcji .
Bonus: tablice zagnieżdżone z
indexOf
icontains
Samy Bencherif przygotował przydatne funkcje na wypadek, gdy szukasz określonego obiektu w zagnieżdżonych tablicach, które są dostępne tutaj: https://jsfiddle.net/SamyBencherif/8352y6yw/
źródło
this[i] !== array[i]
zamiast!=
.equals
zamiastcompare
. Przynajmniej w .NET porównanie zwykle zwraca podpisany znak int wskazujący, który obiekt jest większy od drugiego. Zobacz: Comparer.Compare .Chociaż działa to tylko w przypadku tablic skalarnych (patrz uwaga poniżej), jest krótkie:
Rr, w ECMAScript 6 / CoffeeScript / TypeScript z funkcjami strzałek:
(Uwaga: „skalar” oznacza tutaj wartości, które można bezpośrednio porównać
===
. Tak więc: liczby, ciągi znaków, obiekty według odwołania, funkcje według odwołania. Zobacz odniesienie MDN, aby uzyskać więcej informacji na temat operatorów porównania).AKTUALIZACJA
Z tego, co przeczytałem w komentarzach, sortowanie tablicy i porównywanie może dać dokładny wynik:
Na przykład:
Wtedy powyższy kod dałby
true
źródło
a1.length==a2.length && a1.every((v,i)=>a2.includes(v))
:var a1 =[1,2,3], a2 = [3,2,1];
(var a1 =[1,3,3], a2 = [1,1,3];
nie będzie działać zgodnie z oczekiwaniami)Lubię używać biblioteki Underscore do projektów kodowania tablic / obiektów ... w Underscore i Lodash, niezależnie od tego, czy porównujesz tablice czy obiekty, tak to wygląda:
źródło
_.isEqual([1,2,3], [2,1,3]) => false
isEqual
funkcjonalność, zawsze możesz użyć modułu_.isEqual([1,2,3].sort(), [2,1,3].sort()) => true
Myślę, że jest to najprostszy sposób, aby to zrobić za pomocą JSON stringify, i może być najlepszym rozwiązaniem w niektórych sytuacjach:
Konwertuje to obiekty
a1
ia2
ciągi, aby można je było porównać. Kolejność jest ważna w większości przypadków, ponieważ umożliwia sortowanie obiektu za pomocą algorytmu sortowania pokazanego w jednej z powyższych odpowiedzi.Pamiętaj, że nie porównujesz już obiektu, ale reprezentację ciągu obiektu. To może nie być dokładnie to, czego chcesz.
źródło
Nie jest jasne, co rozumiesz przez „identyczny”. Na przykład, czy tablice
a
ib
poniżej są identyczne (zwróć uwagę na tablice zagnieżdżone)?Oto zoptymalizowana funkcja porównywania tablic, która porównuje kolejno odpowiednie elementy każdej tablicy przy użyciu ścisłej równości i nie dokonuje rekurencyjnego porównywania elementów tablicy, które same są tablicami, co oznacza, że w powyższym przykładzie
arraysIdentical(a, b)
powróciłobyfalse
. Działa w ogólnym przypadku, któregojoin()
rozwiązania JSON i oparte na nim nie będą:źródło
true
. Odpowiedź wyjaśnia, że tak nie będzie. Jeśli chcesz porównać zagnieżdżone tablice, możesz łatwo dodać kontrolę rekurencyjną.Praktyczny sposób
Myślę, że błędem jest twierdzenie, że konkretna implementacja to „Właściwy sposób”, jeśli jest tylko „właściwa” („poprawna”) w przeciwieństwie do „złego” rozwiązania. Rozwiązanie Tomáša stanowi wyraźną poprawę w porównaniu z porównywaniem tablic łańcuchowych, ale to nie znaczy, że jest obiektywnie „właściwe”. Co właściwie jest właściwe ? Czy to jest najszybsze? Czy to jest najbardziej elastyczne? Czy najłatwiej to zrozumieć? Czy debugowanie jest najszybsze? Czy używa najmniej operacji? Czy ma jakieś skutki uboczne? Żadne rozwiązanie nie może mieć wszystkiego najlepszego.
Tomáš mógł powiedzieć, że jego rozwiązanie jest szybkie, ale powiedziałbym również, że jest to niepotrzebnie skomplikowane. Stara się być rozwiązaniem typu „wszystko w jednym”, które działa dla wszystkich tablic, zagnieżdżonych lub nie. W rzeczywistości przyjmuje nawet więcej niż tylko tablice jako dane wejściowe i nadal próbuje udzielić „prawidłowej” odpowiedzi.
Produkty generyczne oferują możliwość ponownego użycia
Moja odpowiedź podejdzie do problemu inaczej. Zacznę od ogólnej
arrayCompare
procedury, która dotyczy tylko przechodzenia przez tablice. Następnie zbudujemy nasze inne podstawowe funkcje porównania, takie jakarrayEqual
iarrayDeepEqual
itpMoim zdaniem najlepszy rodzaj kodu nie wymaga nawet komentarzy i nie jest to wyjątkiem. Tutaj dzieje się tak mało, że można zrozumieć zachowanie tej procedury bez żadnego wysiłku. Pewnie, niektóre ze składni ES6 mogą wydawać się wam teraz obce, ale tylko dlatego, że ES6 jest stosunkowo nowy.
Jak sugeruje typ,
arrayCompare
przyjmuje funkcję porównaniaf
oraz dwie tablice wejściowexs
iys
. W większości przypadków wywołujemyf (x) (y)
każdy element w tablicach wejściowych. Wracamy wcześnie,false
jeślif
zwrot zdefiniowany przez użytkownikafalse
- dzięki&&
ocenie zwarcia. Tak, oznacza to, że komparator może wcześniej przerwać iterację i zapobiec zapętlaniu się przez resztę tablicy wejściowej, gdy nie jest to konieczne.Ścisłe porównanie
Następnie, korzystając z naszej
arrayCompare
funkcji, możemy łatwo stworzyć inne funkcje, których możemy potrzebować. Zaczniemy od elementarnegoarrayEqual
…Proste.
arrayEqual
można zdefiniować zaarrayCompare
pomocą funkcji porównawczej, która porównuje sięa
dob
użycia===
(dla ścisłej równości).Zauważ, że my również definiujemy
equal
jako własną funkcję. Podkreśla to rolęarrayCompare
funkcji wyższego rzędu w wykorzystaniu naszego komparatora pierwszego rzędu w kontekście innego typu danych (Array).Luźne porównanie
Możemy równie łatwo zdefiniować
arrayLooseEqual
za pomocą==
zamiast. Teraz podczas porównywania1
(Liczba) do'1'
(Ciąg) wynikiem będzietrue
…Głębokie porównanie (rekurencyjne)
Prawdopodobnie zauważyłeś, że jest to tylko płytkie porównanie. Z pewnością rozwiązaniem Tomáša jest „The Right Way ™”, ponieważ zawiera niejawne głębokie porównanie, prawda?
Nasza
arrayCompare
procedura jest na tyle wszechstronna, że można ją stosować w taki sposób, że test głębokiej równości jest dziecinnie prosty…Proste. Budujemy głęboki komparator za pomocą innej funkcji wyższego rzędu. Tym razem mamy do pakowania
arrayCompare
przy użyciu niestandardowych porównanie, że sprawdzi, czya
ib
są tablice. Jeśli tak, zastosuj ponownie warrayDeepCompare
innym przypadkua
ib
do komparatora określonego przez użytkownika (f
). To pozwala nam oddzielić zachowanie do głębokiego porównania od tego, jak faktycznie porównujemy poszczególne elementy. Czyli jak pokazuje powyższy przykład, możemy porównać stosując głębokoequal
,looseEqual
lub dowolny inny komparator robimy.Ponieważ
arrayDeepCompare
jest curry, możemy go częściowo zastosować, tak jak w poprzednich przykładachDla mnie jest to już wyraźna poprawa w stosunku do rozwiązania Tomáša, ponieważ w razie potrzeby mogę wyraźnie wybrać płytkie lub głębokie porównanie moich zestawów.
Porównanie obiektów (przykład)
Co teraz, jeśli masz tablicę obiektów lub coś takiego? Może chcesz uznać te tablice za „równe”, jeśli każdy obiekt ma tę samą
id
wartość…Proste. Tutaj użyłem waniliowych obiektów JS, ale ten typ komparatora może działać dla dowolnego typu obiektu; nawet twoje niestandardowe obiekty. Rozwiązanie Tomáša musiałoby zostać całkowicie przerobione, aby obsługiwać ten rodzaj testu równości
Głęboka tablica z obiektami? Żaden problem. Zbudowaliśmy bardzo wszechstronne, ogólne funkcje, dzięki czemu będą działać w szerokim zakresie zastosowań.
Arbitralne porównanie (przykład)
A co, jeśli chcesz dokonać innego rodzaju całkowicie arbitralnego porównania? Może chcę wiedzieć, czy każdy
x
jest większy niż każdyy
…Mniej znaczy więcej
Widać, że faktycznie robimy więcej przy mniejszym kodzie. Nie ma w sobie nic skomplikowanego
arrayCompare
, a każdy stworzony przez nas niestandardowy komparator ma bardzo prostą implementację.Z łatwością możemy dokładnie określić, w jaki sposób chcemy na dwie tablice należy porównać - płytkie, głębokie, ścisłe, luźne, niektóre właściwości obiektu, lub dowolna część obliczeń, lub dowolna kombinacja tych form - wszystko za pomocą jednej procedury ,
arrayCompare
. Może nawet wymarzyszRegExp
komparator! Wiem, jak dzieci uwielbiają te wyrażenia regularne…Czy to jest najszybsze? Nie. Ale prawdopodobnie nie musi tak być. Jeśli szybkość jest jedyną miarą używaną do pomiaru jakości naszego kodu, wiele naprawdę świetnych kodów zostałoby wyrzuconych - dlatego nazywam to podejście Praktycznym . Lub może być bardziej sprawiedliwy, praktyczny sposób. Ten opis jest odpowiedni dla tej odpowiedzi, ponieważ nie twierdzę, że ta odpowiedź jest praktyczna w porównaniu z innymi odpowiedziami; jest to obiektywnie prawdziwe. Osiągnęliśmy wysoki stopień praktyczności przy bardzo małym kodzie, o którym bardzo łatwo jest myśleć. Żaden inny kod nie może powiedzieć, że nie zasłużyliśmy na ten opis.
Czy to sprawia, że jest to „właściwe” rozwiązanie dla Ciebie? To zależy od ciebie . I nikt inny nie może tego dla ciebie zrobić; tylko ty wiesz, jakie są twoje potrzeby. W prawie wszystkich przypadkach cenię prosty, praktyczny i wszechstronny kod nad sprytnym i szybkim rodzajem. To, co cenisz, może się różnić, więc wybierz to, co Ci odpowiada.
Edytować
Moja stara odpowiedź bardziej koncentrowała się na rozkładaniu
arrayEqual
na małe procedury. To ciekawe ćwiczenie, ale nie jest to najlepszy (najbardziej praktyczny) sposób podejścia do tego problemu. Jeśli jesteś zainteresowany, możesz zobaczyć tę historię zmian.źródło
arrayCompare
? Tak, funkcja jest curry, ale różni się odsome
ievery
.arrayCompare
porównuje komparator i dwie tablice. Wybrałem specyficzną nazwę ogólną, ponieważ możemy porównywać tablice za pomocą dowolnej dowolnej funkcji. Funkcja jest curry, więc można ją wyspecjalizować w tworzeniu nowych funkcji porównywania tablic (nparrayEqual
.). Czy możesz zaproponować lepsze imię? Jakie obszary Twoim zdaniem wymagają dodatkowych komentarzy lub wyjaśnień? Z przyjemnością omawiam ^ _ ^W duchu pierwotnego pytania:
Testy wydajności przeprowadziłem na niektórych zaproponowanych tutaj prostszych sugestiach z następującymi wynikami (od szybkiego do wolnego):
natomiast (67%) przez Tim Down
co (69%) według użytkownika2782196
zmniejszyć (74%) o DEI
dołączyć i toString (78%) przez Gaizka Allende i vivek
połowa do String (90%) autorstwa Victora Palomo
stringify (100%) przez radtek
źródło
Array.from({length: 1000}).map((a,v)=>
$ {v}.padStart(10,2));
Opierając się na odpowiedzi Tomáša Zato, zgadzam się, że iteracja po tablicach jest najszybsza. Dodatkowo (jak już inni powiedzieli), funkcję należy nazwać równą / równą, a nie porównywać. W związku z tym zmodyfikowałem tę funkcję, aby obsługiwała porównywanie tablic dla podobieństwa - tj. Mają te same elementy, ale są nieczynne - do użytku osobistego i pomyślałem, że wrzucę to tutaj, aby wszyscy mogli to zobaczyć.
Ta funkcja przyjmuje dodatkowy parametr strict, który domyślnie ma wartość true. Ten ścisły parametr określa, czy tablice muszą być całkowicie równe zarówno pod względem zawartości, jak i kolejności tych treści, czy po prostu zawierają tę samą zawartość.
Przykład:
Napisałem również szybkie jsfiddle z funkcją i tym przykładem:
http://jsfiddle.net/Roundaround/DLkxX/
źródło
Mimo że ma wiele odpowiedzi, które, jak sądzę, są pomocne:
Pytanie nie mówi, jak będzie wyglądać struktura tablicy, więc jeśli wiesz na pewno, że nie będziesz mieć zagnieżdżonych tablic ani obiektów w tablicy (zdarzyło mi się, dlatego do tego doszedłem odpowiedź) powyższy kod będzie działał.
Co się dzieje, używamy operatora spreadu (...) do łączenia obu tablic, a następnie używamy Setu, aby wyeliminować wszelkie duplikaty. Gdy już to zrobisz, możesz porównać ich rozmiary, jeśli wszystkie trzy tablice mają taki sam rozmiar, możesz przejść.
Ta odpowiedź ignoruje również kolejność elementów , jak już powiedziałem, przydarzyła mi się dokładna sytuacja, więc może ktoś w tej samej sytuacji może skończyć tutaj (tak jak ja).
Edytuj1.
Odpowiadając na pytanie Dmitrija Grinko: „Dlaczego użyłeś tutaj operatora rozprzestrzeniania (...) - ... nowego zestawu? To nie działa”
Rozważ ten kod:
Dostaniesz
Aby pracować z tą wartością, musisz użyć niektórych właściwości Set (patrz https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set ). Z drugiej strony, gdy używasz tego kodu:
Dostaniesz
To różnica, ta pierwsza dałaby mi Set, to też działałoby, ponieważ mogłem uzyskać rozmiar tego Seta, ale druga daje mi potrzebną tablicę, co jest bardziej bezpośrednie na rozdzielczość.
źródło
W tych samych wierszach, co JSON.encode, należy użyć join ().
Jedynym problemem jest to, czy zależy Ci na typach, które testują ostatnie porównania. Jeśli zależy Ci na typach, będziesz musiał zapętlić.
Jeśli kolejność pozostanie niezmieniona, a nie tylko pętla, sortowanie nie jest potrzebne.
źródło
.join()
. Być może, jeśli podasz swoje drugie rozwiązanie jako podstawowe (ponieważ jest lepsze, choć bezzębne w przypadku tablic wielowymiarowych), nie oceniłbym cię w ten sposób. Do tej pory zanotowałem wszystkie odpowiedzi, które konwertują tablice na ciągi. Również głosowałem za wszystkimi, którzy używają tego we właściwy sposób, na wypadek, gdybyś musiał to wiedzieć. Oznacza to odpowiedź @Tim Down i Bireys one.checkArrays([1,2,3] , ["1,2",3]) == true
kończy się niepowodzeniem: i jest bardzo mało prawdopodobne, że tak właśnie się stanie!join()
ten sposób powoduje subtelny błąd!Oto wersja maszynopisu:
Niektóre przypadki testowe dla mokki:
źródło
Jeśli używasz środowiska testowego, takiego jak Mocha, z biblioteką asercji Chai , możesz użyć głębokiej równości do porównania tablic.
Powinno to zwrócić wartość prawdy tylko wtedy, gdy tablice mają równe elementy przy odpowiednich indeksach.
źródło
Jeśli są to dwie tablice liczb lub ciągów znaków, jest to szybka jednowierszowa
źródło
[11]
. Dość oczywiste, dlaczego tak się dzieje i jak to naprawić.W moim przypadku porównywane tablice zawierają tylko liczby i ciągi znaków. Ta funkcja pokaże, czy tablice zawierają te same elementy.
Przetestujmy to!
źródło
are_arrs_equal([1,2], [2,1])
. Zobacz także inne dyskusje na tej stronie, aby dowiedzieć się, dlaczego tworzenie łańcuchów jest niepotrzebne, kruche i niewłaściwe.are_arrs_equal([1,2], [2,1])
zwracatrue
zgodnie z oczekiwaniami. Być może to rozwiązanie nie jest idealne, ale zadziałało dla mnie.are_arrs_match([1,2], ["1,2"])
(zwrotytrue
). I pamiętaj, żethe sort()
wywołanie zmodyfikuje tablice wejściowe - może to nie być pożądane.Porównuje to 2 nieposortowane tablice:
źródło
Aby uzyskać tablicę liczb, spróbuj:
Pokaż fragment kodu
Uwaga: ta metoda nie będzie działać, gdy tablica zawiera również ciągi znaków, np
a2 = [1, "2,3"]
.źródło
Możemy to zrobić funkcjonalnie, używając
every
( https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Array/every )źródło
Twój kod nie będzie odpowiednio traktował sprawy, gdy obie tablice mają te same elementy, ale nie w tej samej kolejności.
Spójrz na mój kod z twoim przykładem, który porównuje dwie tablice, których elementami są liczby, możesz go zmodyfikować lub rozszerzyć dla innych typów elementów (używając .join () zamiast .toString ()).
źródło
Oto moje rozwiązanie:
Działa z dowolną zagnieżdżoną strukturą danych i oczywiście ignoruje metody obiektów. Nawet nie myśl o rozszerzeniu Object.prototype za pomocą tej metody, gdy raz spróbowałem, jQuery się zepsuł;)
W przypadku większości macierzy jest to wciąż szybsze niż w przypadku większości rozwiązań do serializacji. Jest to prawdopodobnie najszybsza metoda porównywania tablic rekordów obiektów.
źródło
equal({}, {a:1})
iequal({}, null)
to pomija błędy:equal({a:2}, null)
Tak to zrobiłem.
źródło
Porównywanie 2 tablic:
funkcja wywoływania
źródło
Wierzę w prosty
JS
i zrozumiały sposóbECMAScript 2015
, który jest słodki i prosty do zrozumienia.mam nadzieję, że to komuś pomoże.
źródło
Rozszerzenie pomysłu Tomáša Zato. Array.prototype.compare Tomasa powinno być w rzeczywistości nazywane Array.prototype.compareIdentical.
Przekazuje:
Ale zawiedzie:
Oto lepsza (moim zdaniem) wersja:
http://jsfiddle.net/igos/bcfCY/
źródło
////// LUB ///////
źródło
Inne podejście z bardzo małą liczbą kodów (użycie Array redukowania i Array obejmuje ):
Jeśli chcesz porównać również równość kolejności:
Te
length
, zapewnia Sprawdź, czy zestaw elementów w jednej tablicy nie jest tylko podzbiorem drugiego.Reduktor służy do przechodzenia przez jedną tablicę i wyszukiwania każdego elementu w drugiej tablicy. Jeśli jeden element nie zostanie znaleziony, funkcja zmniejszania powróci
false
.źródło
Proste podejście:
źródło
Już kilka świetnych odpowiedzi, ale chciałbym podzielić się innym pomysłem, który okazał się niezawodny w porównaniu tablic. Możemy porównać dwie tablice za pomocą JSON.stringify () . Stworzy ciąg z tablicy, a tym samym porówna dwa uzyskane ciągi z dwóch tablic dla równości
źródło
Rekurencyjne i działa na tablicach NESTED :
źródło
Działa z MULTIPLE argumentami z tablicami NESTED :
źródło
źródło