Jestem pewien, że istnieje dobry powód, ale czy ktoś mógłby wyjaśnić, dlaczego java.util.Set
brakuje interfejsu get(int Index)
lub jakąkolwiek podobną get()
metodę?
Wygląda na to, że zestawy świetnie nadają się do wkładania rzeczy, ale nie mogę znaleźć eleganckiego sposobu na odzyskanie z nich pojedynczego przedmiotu.
Jeśli wiem, że chcę pierwszy element, mogę go użyć set.iterator().next()
, ale w przeciwnym razie wydaje się, że muszę rzucić na tablicę, aby pobrać element o określonym indeksie?
Jakie są odpowiednie sposoby pobierania danych z zestawu? (inne niż użycie iteratora)
Jestem pewien, że fakt wykluczenia go z interfejsu API oznacza, że istnieje dobry powód, aby tego nie robić - czy ktoś mógłby mnie oświecić?
EDYCJA: Niektóre bardzo świetne odpowiedzi tutaj, a kilka mówi „więcej kontekstu”. Konkretnym scenariuszem był test dbUnit, w którym mogłem racjonalnie stwierdzić, że zwrócony zestaw z zapytania zawierał tylko 1 element i próbowałem uzyskać dostęp do tego elementu.
Jednak pytanie jest ważniejsze bez scenariusza, ponieważ pozostaje bardziej skoncentrowane:
Jaka jest różnica między zestawem a listą .
Dziękujemy wszystkim za fantastyczne odpowiedzi poniżej.
źródło
Odpowiedzi:
Ponieważ zestawy nie mają kolejności. Niektóre implementacje tak robią (szczególnie te implementujące
java.util.SortedSet
interfejs), ale nie jest to ogólna właściwość zestawów.Jeśli próbujesz używać zestawów w ten sposób, powinieneś rozważyć użycie listy.
źródło
W rzeczywistości jest to powtarzające się pytanie podczas pisania aplikacji JavaEE, które używają mapowania obiektowo-relacyjnego (na przykład przy Hibernacji); a spośród wszystkich osób, które tu odpowiedziały, Andreas Petersson jest jedynym, który zrozumiał prawdziwy problem i zaoferował poprawną odpowiedź: Java nie ma UniqueList! (lub możesz też nazwać to OrDERSet lub IndexedSet).
Maxwing wspomniał o tym przypadku użycia (w którym potrzebujesz uporządkowanych ORAZ unikalnych danych) i zasugerował SortedSet, ale nie tego naprawdę potrzebował Marty Pitt.
Ten „IndexedSet” NIE jest tym samym, co SortedSet - w SortedSet elementy są sortowane za pomocą komparatora (lub przy użyciu ich „naturalnego” uporządkowania).
Zamiast tego jest bliżej LinkedHashSet (który inni też sugerowali), a jeszcze bardziej do (również nieistniejącego) „ArrayListSet”, ponieważ gwarantuje, że elementy są zwracane w tej samej kolejności, w jakiej zostały wstawione.
Ale LinkedHashSet jest implementacją, a nie interfejsem! Potrzebny jest interfejs IndexedSet (lub ListSet, OrdersSet lub UniqueList)! Pozwoli to programiście określić, że potrzebuje kolekcji elementów o określonej kolejności i bez duplikatów, a następnie utworzyć instancję z dowolną implementacją (na przykład implementacją zapewnianą przez Hibernację).
Ponieważ JDK jest oprogramowaniem typu open source, być może ten interfejs zostanie w końcu zawarty w Javie 7 ...
źródło
ListOrderedSet
to, czego OP potrzebował 7 lat temu (a ja potrzebowałem dzisiaj).What is needed is an IndexedSet (or ListSet, or OrderedSet, or UniqueList)...
i zignorowałem...interface
. Przepraszam za to!Wystarczy dodać jeden punkt, który nie został wymieniony w odpowiedzi mmyersa .
Powinieneś także zapoznać się z
SortedSet
interfejsem (którego najczęstszą implementacją jestTreeSet
).SortedSet to zestaw (tzn. Elementy są unikalne), który jest utrzymywany w kolejności przez naturalne uporządkowanie elementów lub za pomocą niektórych
Comparator
. Możesz łatwo uzyskać dostęp do pierwszego i ostatniego elementu za pomocąfirst()
ilast()
metod. ASortedSet
przydaje się od czasu do czasu, gdy musisz zachować swoją kolekcję bez duplikatów i zamówić w określony sposób.Edycja : jeśli potrzebujesz zestawu, którego elementy są przechowywane w kolejności wstawiania (podobnie jak lista), spójrz na
LinkedHashSet
.źródło
Ten rodzaj prowadzi do pytania, kiedy powinieneś użyć zestawu, a kiedy powinieneś użyć listy. Zwykle rada brzmi:
Czwarty przypadek, który pojawia się często, to, że nie potrzebujesz żadnego. W tym przypadku niektórzy programiści korzystają z list, a niektórzy z zestawami. Osobiście uważam za bardzo szkodliwe widzieć zestaw jako listę bez zamawiania - ponieważ tak naprawdę jest to zupełnie inna bestia. O ile nie potrzebujesz rzeczy takich jak zestaw unikatowości lub zestaw równości, zawsze faworyzuj listy.
źródło
Nie jestem pewien, czy ktokolwiek napisał to dokładnie w ten sposób, ale musisz zrozumieć, co następuje:
W zestawie nie ma „pierwszego” elementu.
Ponieważ, jak powiedzieli inni, zestawy nie mają kolejności. Zestaw jest matematyczną koncepcją, która w szczególności nie obejmuje zamawiania.
Oczywiście, twój komputer nie może tak naprawdę przechowywać listy rzeczy, które nie są uporządkowane w pamięci. To musi mieć jakieś zamówienie. Wewnętrznie jest to tablica, połączona lista lub coś takiego. Ale tak naprawdę nie wiesz, co to jest, i tak naprawdę nie ma pierwszego elementu; element, który wychodzi „pierwszy”, wychodzi w ten sposób przez przypadek i może nie być pierwszy raz następnym razem. Nawet jeśli podjąłeś kroki w celu „zagwarantowania” określonego pierwszego elementu, nadal pojawia się on przypadkowo, ponieważ akurat udało ci się go poprawnie zastosować do jednej konkretnej implementacji zestawu; inna implementacja może nie działać w ten sposób z tym, co zrobiłeś. W rzeczywistości możesz nie wiedzieć, jakiej implementacji używasz tak dobrze, jak myślisz.
Ludzie wpadają na to WSZYSTKO. THE. CZAS. z systemami RDBMS i nie rozumiem. Zapytanie RDBMS zwraca zestaw rekordów. Jest to ten sam typ zestawu z matematyki: nieuporządkowany zbiór elementów, tylko w tym przypadku elementy są rekordami. Wynik zapytania RDBMS nie ma żadnej gwarantowanej kolejności, chyba że użyjesz klauzuli ORDER BY, ale przez cały czas ludzie to zakładają, a następnie wyzwalają się pewnego dnia, gdy kształt ich danych lub kodu zmienia się nieznacznie i uruchamia optymalizator zapytań do działania w inny sposób i nagle wyniki nie pojawiają się w oczekiwanej kolejności. Są to zazwyczaj ludzie, którzy nie zwracali uwagi w klasie bazy danych (lub podczas czytania dokumentacji lub samouczków), gdy wyjaśniono im z góry, że wyniki zapytania nie mają gwarantowanej kolejności.
źródło
Set
jestIterable
.brakuje niektórych struktur danych w standardowych kolekcjach Java.
Torba (jak zestaw, ale może zawierać elementy wiele razy)
UniqueList (lista uporządkowana, każdy element może zawierać tylko raz)
wygląda na to, że w tym przypadku potrzebujesz unikalnej listy
jeśli potrzebujesz elastycznych struktur danych, możesz być zainteresowany kolekcjami Google
źródło
To prawda, elementy w zestawie nie są uporządkowane z definicji kolekcji zestawu. Dlatego nie mogą być dostępne za pomocą indeksu.
Ale dlaczego nie mamy metody get (object), nie podając indeksu jako parametru, ale obiekt równy temu, którego szukamy? W ten sposób możemy uzyskać dostęp do danych elementu w zestawie, po prostu znając jego atrybuty używane przez metodę równości.
źródło
Jeśli zamierzasz wykonywać wiele losowych wejść według indeksu w zestawie, możesz uzyskać widok tablicy jego elementów:
Istnieją jednak dwie główne wady:
źródło
Wynika to z faktu, że Set gwarantuje tylko wyjątkowość, ale nie mówi nic o optymalnych wzorcach dostępu lub użytkowania. Tj. Zestaw może być listą lub mapą, z których każda ma bardzo różne właściwości wyszukiwania.
źródło
Jedynym powodem, dla którego mogę wymyślić użycie indeksu numerycznego w zestawie, jest iteracja. W tym celu użyj
źródło
Natrafiłem na sytuacje, w których naprawdę chciałem Posortować zestaw z dostępem przez indeks (zgadzam się z innymi plakatami, że dostęp do nieposortowanego zestawu z indeksem nie ma sensu). Przykładem może być drzewo, w którym chciałem, aby dzieci były sortowane, a duplikowanie dzieci nie było dozwolone.
Potrzebowałem dostępu za pomocą indeksu, aby je wyświetlić, a zestaw atrybutów przydał się, aby skutecznie wyeliminować duplikaty.
Nie znajdując żadnej odpowiedniej kolekcji w kolekcjach java.util lub google, uznałem, że to proste. Podstawowym pomysłem jest zawinięcie SortedSet i utworzenie listy, gdy wymagany jest dostęp za pośrednictwem indeksu (i zapomnienie listy po zmianie SortedSet). Działa to oczywiście tylko efektywnie, gdy zmieni się zawinięty SortedSet i dostęp do listy jest oddzielony w czasie istnienia kolekcji. W przeciwnym razie zachowuje się jak często sortowana lista, tj. Zbyt wolno.
W przypadku dużej liczby dzieci poprawiło się to znacznie w porównaniu z listą, którą posortowałem za pośrednictwem Collections.sort.
źródło
Należy pamiętać, że tylko 2 podstawowe struktury danych są dostępne poprzez indeks.
O(1)
złożonością czasową, aby osiągnąćget(int index)
działanie.O(n)
złożonością czasową, aby osiągnąćget(int index)
działanie.W Javie
ArrayList
jest implementowany przy użyciu struktury danych Array .Podczas gdy struktura danych zestawu zwykle może być zaimplementowana za pomocą struktury danych HashTable / HashMap lub BalancedTree , w celu szybkiego wykrycia, czy element istnieje i dodania nieistniejącego elementu, zwykle dobrze zaimplementowany zestaw może osiągnąć operację
O(1)
złożoności czasowejcontains
. W JavieHashSet
jest najczęściej stosowaną implementacją Seta , jest implementowana przez wywołanieHashMap
API iHashMap
jest implementowana za pomocą oddzielnego łączenia z listami połączonymi (kombinacja Array i LinkedList ).Ponieważ zestaw można zaimplementować za pomocą innej struktury danych, nie ma
get(int index)
na to metody.źródło
Data.Sequence.lookup
funkcja Haskella ) umożliwiają również dostęp przez indeks (O(1)
bliżej końca wO(log n)
pobliżu środka, dokładniejO(min(log(k), log(n-k)))
), również drzewa binarne (patrzData.Set.lookupIndex
funkcja Haskella ). Zatem twoje początkowe stwierdzenie, że „Uwaga: tylko 2 podstawowe struktury danych są dostępne za pośrednictwem indeksu” jest nieprawidłowe.Powód, dla którego ustawiony jest interfejs nie ma wywołania typu indeks ani nawet czegoś bardziej podstawowego, takiego jak first () lub last (), jest to, że jest to operacja niejednoznaczna, a zatem potencjalnie niebezpieczna. Jeśli metoda zwraca Set, a ty wywołujesz metodę powiedzmy first (), jaki jest oczekiwany wynik, biorąc pod uwagę, że ogólny zestaw nie daje żadnych gwarancji przy zamówieniu? Wynikowy obiekt może bardzo różnić się między poszczególnymi wywołaniami metody, lub może nie wprawić cię w fałszywe poczucie bezpieczeństwa, dopóki biblioteka, której używasz, nie zmieni zmian pod implementacją, a teraz okaże się, że cały kod się psuje Bez szczególnego powodu.
Podane tutaj sugestie dotyczące obejść są dobre. Jeśli potrzebujesz dostępu indeksowanego, skorzystaj z listy. Zachowaj ostrożność przy korzystaniu z iteratorów lub tablicy z ogólnym zestawem, ponieważ a) nie ma gwarancji na zamówienie ib) nie ma gwarancji, że zamówienie nie zmieni się przy kolejnych wywołaniach lub różnych implementacjach bazowych. Jeśli potrzebujesz czegoś pomiędzy, SortedSet lub LinkedHashSet jest tym, czego potrzebujesz.
// Chciałbym, żeby interfejs Set miał element get-random.
źródło
java.util.Set
to zbiór niezamówionych przedmiotów. Nie ma sensu, jeśli Set ma get (int index), ponieważ Set nie ma indeksu, a ty tylko możesz odgadnąć wartość.Jeśli naprawdę tego chcesz, koduj metodę, aby uzyskać losowy element z Seta.
źródło
Możesz to zrobić
new ArrayList<T>(set).get(index)
źródło
new ArrayList<T>(t).get(0)
myślę, że istnieje uzasadniony sprzeciw wobec pomysłu uzyskania określonego elementu z zestawu przez indeks. Byłoby jednak miło, gdyby Set miał funkcję only () członka, która dla zestawów o rozmiarze 1 zapewniała łatwy dostęp do jedynego elementu w zestawie. Pozwoliłoby to zaoszczędzić wspomniananew ArrayList
lubfor (Foo foo : foos) { return foo; }
Jeśli nie przeszkadza ci sortowanie zestawu, możesz zainteresować się projektem indeksu drzewa indeksowanego .
Ulepszone TreeSet / TreeMap zapewnia dostęp do elementów poprzez indeks lub uzyskanie indeksu elementu. A implementacja opiera się na aktualizacji wag węzłów w drzewie RB. Więc nie ma iteracji ani kopii zapasowej listy tutaj.
źródło
Zestaw jest interfejsem, a niektóre z jego klas implementacji to HashSet, TreeSet i LinkedHashSet. Używa HashMap pod maską do przechowywania wartości. Ponieważ HashMap nie zachowuje kolejności, nie można uzyskać wartości według indeksu.
Musisz teraz myśleć o tym, jak Set używa HashMap, ponieważ HashMap przechowuje parę klucz-wartość, ale Set nie. ważne pytanie. gdy dodajesz element do zestawu, wewnętrznie zachowuje on HashMap, gdzie klucz jest elementem, który chcesz wprowadzić w zestawie, a wartość jest stałą manekina. Poniżej znajduje się wewnętrzna implementacja funkcji add. Dlatego wszystkie klucze w HashMap będą miały tę samą stałą wartość.
źródło
Set
implementacje używająHashMap
pod maską do przechowywania wartości. Czy możesz uzasadnić to roszczenieTreeSet
?the keys in the HashMap will have the same constant value
klucze wHashMap
mapie zostaną przypisane do tego samego niezmiennegoObject
Aby uzyskać element w zestawie, używam następującego:
źródło
T
zdefiniowane? Dlaczegoif (true)
?