Pracuję w JavaScript. Chciałbym przechowywać listę unikalnych , nieuporządkowanych wartości ciągów, o następujących właściwościach:
- szybki sposób na pytanie „czy A jest na liście”?
- szybki sposób na „usunięcie A z listy, jeśli istnieje na liście”
- szybki sposób na dodanie „A do listy, jeśli jeszcze jej nie ma”.
To, czego naprawdę chcę, to zestaw. Wszelkie sugestie dotyczące najlepszego sposobu naśladowania zestawu w JavaScript?
To pytanie zaleca użycie obiektu z właściwościami przechowywania kluczy, a wszystkie wartości ustawione na true: czy to rozsądny sposób?
javascript
Richard
źródło
źródło
Odpowiedzi:
Jeśli programujesz w środowisku obsługującym ES6 (takim jak node.js, konkretna przeglądarka z możliwościami ES6, których potrzebujesz lub transponuj kod ES6 dla swojego środowiska), możesz użyć
Set
obiektu wbudowanego w ES6 . Ma bardzo ładne możliwości i może być używany tak, jak jest w twoim otoczeniu.W przypadku wielu prostych rzeczy w środowisku ES5 korzystanie z obiektu działa bardzo dobrze. Jeśli
obj
jest to twój obiekt iA
jest zmienną, która ma wartość, na której chcesz operować w zestawie, możesz to zrobić:Kod inicjalizacji:
Pytanie 1: Jest
A
na liście:Pytanie 2: Usuń „A” z listy, jeśli tam jest:
Pytanie 3: Dodaj „A” do listy, jeśli jeszcze jej nie było
Aby uzyskać kompletność, sprawdź, czy
A
to, jest na liście, jest nieco bezpieczniejszy dzięki temu:z powodu potencjalnego konfliktu między wbudowanymi metodami i / lub właściwościami w obiekcie podstawowym, takim jak
constructor
właściwość.Pasek boczny na ES6: bieżąca działająca wersja ECMAScript 6 lub coś o nazwie ES 2015 ma wbudowany obiekt Set . Jest teraz zaimplementowany w niektórych przeglądarkach. Ponieważ dostępność przeglądarki zmienia się z czasem, możesz poszukać w wierszu
Set
w tabeli zgodności ES6, aby zobaczyć bieżący stan dostępności przeglądarki.Jedną z zalet wbudowanego obiektu Set jest to, że nie zmusza wszystkich kluczy do łańcucha tak jak Obiekt, więc możesz mieć zarówno 5, jak i „5” jako osobne klucze. I możesz nawet używać Obiektów bezpośrednio w zestawie bez konwersji łańcucha. Oto artykuł opisujący niektóre możliwości i dokumentację MDN na obiekcie Set.
Napisałem polifill dla obiektu zestawu ES6, abyś mógł zacząć z niego korzystać teraz i automatycznie przełączy się na wbudowany obiekt zestawu, jeśli przeglądarka go obsługuje. Ma to tę zaletę, że piszesz kod zgodny z ES6, który będzie działał aż do IE7. Ale są też pewne wady. Interfejs zestawu ES6 wykorzystuje iteratory ES6, dzięki czemu możesz robić takie rzeczy
for (item of mySet)
a on będzie automatycznie iterował przez zestaw dla Ciebie. Ale tego rodzaju funkcji językowych nie można zaimplementować za pomocą funkcji polifill. Nadal możesz iterować zestaw ES6 bez korzystania z nowych funkcji języków ES6, ale szczerze mówiąc bez nowych funkcji języka, nie jest to tak wygodne, jak inny interfejs zestawu, który przedstawiam poniżej.Możesz zdecydować, który z nich będzie dla Ciebie najlepszy po zapoznaniu się z obydwoma. Zestaw wypełnień ES6 znajduje się tutaj: https://github.com/jfriend00/ES6-Set .
Do twojej wiadomości, w moich własnych testach zauważyłem, że implementacja zestawu Firefox v29 nie jest w pełni aktualna w bieżącym szkicu specyfikacji. Na przykład nie można łączyć
.add()
wywołań metod, takich jak opisy specyfikacji i obsługa wielu wypełniaczy. Jest to prawdopodobnie kwestia specyfikacji w ruchu, ponieważ nie została jeszcze sfinalizowana.Obiekty zestawu gotowego: Jeśli chcesz już zbudować obiekt, który ma metody działania na zestawie, którego można używać w dowolnej przeglądarce, możesz użyć szeregu różnych gotowych obiektów, które implementują różne typy zestawów. Istnieje miniSet, który jest małym kodem, który implementuje podstawy obiektu ustawionego. Ma także bardziej bogaty w funkcje obiekt zestawu i kilka pochodnych, w tym Słownik (pozwala przechowywać / odzyskiwać wartość dla każdego klucza) i ObjectSet (pozwala zachować zestaw obiektów - albo obiekty JS, albo obiekty DOM, w których albo funkcja, która generuje unikalny klucz dla każdego lub ObjectSet wygeneruje klucz dla Ciebie).
Oto kopia kodu miniSet (najbardziej aktualny kod znajduje się tutaj na github ).
źródło
Object.keys(obj)
.Object.keys()
wymaga IE9, FF4, Safari 5, Opera 12 lub nowszej. Jest polyfill dla starszych przeglądarek tutaj .obj.hasOwnProperty(prop)
do kontroli członkostwa. UżyjObject.prototype.hasOwnProperty.call(obj, prop)
zamiast tego, co działa, nawet jeśli „zestaw” zawiera wartość"hasOwnProperty"
.Możesz utworzyć Obiekt bez właściwości takich jak
który może działać jako zestaw i eliminuje potrzebę użycia
hasOwnProperty
.źródło
set = {}
go użyjesz , odziedziczy on wszystkie właściwości z Object (np.toString
), Więc będziesz musiał sprawdzić ładowność zestawu (właściwości, które dodałeś) za pomocąhasOwnProperty
inif (A in set)
set[A]=true
instrukcji dla każdego elementu, który chcesz dodać zamiast tylko jednego inicjatora?s = Object.create(null);s["thorben"] = true;ss = Object.create(s)
Począwszy od ECMAScript 6, struktura danych Set jest funkcją wbudowaną . Zgodność z wersjami node.js można znaleźć tutaj .
źródło
in
nie działa, ponieważSet
obiekty nie mają swoich elementów jako właściwości, co byłoby złe, ponieważ zestawy mogą zawierać elementy dowolnego typu, ale właściwości są łańcuchami. Możesz użyćhas
:Set([1,2]).has(1)
W wersji ES6 Javascript masz wbudowany typ dla zestawu ( sprawdź kompatybilność z przeglądarką ).
Aby dodać element do zestawu, którego po prostu używasz
.add()
, który uruchamia sięO(1)
i albo dodaje element do zestawu (jeśli nie istnieje), albo nic nie robi, jeśli już tam jest. Możesz dodać element dowolnego typu (tablice, ciągi, liczby)Aby sprawdzić liczbę elementów w zestawie, możesz po prostu użyć
.size
. Działa również wO(1)
Aby usunąć element z zestawu użyj
.delete()
. Zwraca true, jeśli wartość tam była (i została usunięta), i false, jeśli wartość nie istniała. Działa również wO(1)
.Aby sprawdzić, czy element istnieje w zestawie
.has()
, zwraca true, jeśli element jest w zestawie, a false w przeciwnym razie. Działa również wO(1)
.Oprócz metod, które chciałeś, istnieje kilka dodatkowych:
numbers.clear();
po prostu usunie wszystkie elementy z zestawunumbers.forEach(callback);
iterowanie po wartościach zestawu w kolejności wstawianianumbers.entries();
utwórz iterator wszystkich wartościnumbers.keys();
zwraca klucze zestawu, który jest taki sam jaknumbers.values()
Istnieje również zestaw słabych punktów, który pozwala dodawać tylko wartości typu obiektowego.
źródło
.add()
uruchomień w O (1)? Intryguje mnie to,Rozpocząłem wdrażanie zestawów, które obecnie działają całkiem dobrze z liczbami i łańcuchami. Moim głównym celem była operacja różnicowa, więc starałem się, aby była jak najbardziej wydajna. Widoki i recenzje kodów są mile widziane!
https://github.com/mcrisc/SetJS
źródło
Właśnie zauważyłem, że biblioteka d3.js ma implementację zestawów, map i innych struktur danych. Nie mogę kłócić się o ich skuteczność, ale sądząc po tym, że jest to popularna biblioteka, musi być tym, czego potrzebujesz.
Dokumentacja jest tutaj
Dla wygody kopiuję z linku (pierwsze 3 funkcje są interesujące)
Tworzy nowy zestaw. Jeśli określono tablicę, dodaje podaną tablicę wartości ciągów do zwróconego zestawu.
Zwraca wartość true tylko wtedy, gdy ten zestaw zawiera wpis dla określonego ciągu wartości.
Dodaje określony ciąg wartości do tego zestawu.
Jeśli zestaw zawiera określony ciąg wartości, usuwa go i zwraca wartość true. W przeciwnym razie ta metoda nic nie robi i zwraca false.
Zwraca tablicę wartości ciągów w tym zestawie. Kolejność zwracanych wartości jest dowolna. Może być używany jako wygodny sposób obliczania unikalnych wartości dla zestawu ciągów. Na przykład:
d3.set ([„foo”, „bar”, „foo”, „baz”]). values (); // „foo”, „bar”, „baz”
Wywołuje określoną funkcję dla każdej wartości w tym zestawie, przekazując wartość jako argument. Ten kontekst funkcji jest tym zestawem. Zwraca niezdefiniowany. Kolejność iteracji jest dowolna.
Zwraca wartość true tylko wtedy, gdy ten zestaw ma wartości zerowe.
Zwraca liczbę wartości w tym zestawie.
źródło
Tak, to rozsądny sposób - to wszystko, czym jest obiekt (cóż, w tym przypadku użycia) - kilka kluczy / wartości z bezpośrednim dostępem.
Przed dodaniem musisz sprawdzić, czy już tam jest, lub jeśli musisz tylko wskazać obecność, „dodanie” go ponownie niczego nie zmienia, po prostu ustawia go ponownie na obiekcie.
źródło