Jak zakomunikować, że kolejność wstawiania ma znaczenie na mapie?

24

Pobieram zestaw krotek z bazy danych i umieszczam na mapie. Zapytanie do bazy danych jest kosztowne.

Nie ma oczywistej naturalnej kolejności elementów na mapie, ale kolejność wstawiania ma jednak znaczenie. Sortowanie mapy byłoby ciężką operacją, więc chcę tego uniknąć, biorąc pod uwagę, że wynik zapytania jest już posortowany tak, jak tego chcę. Dlatego właśnie przechowuję wynik zapytania w LinkedHashMapi zwracam mapę z metody DAO:

public LinkedHashMap<Key, Value> fetchData()

Mam metodę, processDataktóra powinna wykonać pewne przetwarzanie na mapie - modyfikując niektóre wartości, dodając nowe klucze / wartości. Jest zdefiniowany jako

public void processData(LinkedHashMap<Key, Value> data) {...}

Jednak kilka linterów (Sonar itp.) Narzeka, że typem „danych” powinien być interfejs, taki jak „Mapa”, a nie implementacja „LinkedHashMap” ( kałamarnica S1319 ).
Więc w zasadzie mówi, że powinienem był

public void processData(Map<Key, Value> data) {...}

Chcę jednak, aby sygnatura metody mówiła, że kolejność map ma znaczenie - ma znaczenie dla algorytmu w processData- dzięki czemu moja metoda nie jest przekazywana po prostu losową mapą.

Nie chcę używać SortedMap, ponieważ to (z javadoc zjava.util.SortedMap ) „jest uporządkowane zgodnie z naturalną kolejnością jego kluczy lub przez komparator zwykle dostarczany w czasie tworzenia posortowanej mapy”.

Moje klucze nie mają naturalnej kolejności , a tworzenie Komparatora, który nic nie robi, wydaje się pełne.

I nadal chciałbym, aby była to mapa, aby skorzystać z putunikania duplikatów kluczy itp. Jeśli nie, datamogłaby to być List<Map.Entry<Key, Value>>.

Jak więc powiedzieć, że moja metoda chce mapy, która jest już posortowana ? Niestety nie ma java.util.LinkedMapinterfejsu, inaczej bym go użył.

Vidar S. Ramdal
źródło

Odpowiedzi:

56

Więc użyj LinkedHashMap.

Tak , w miarę możliwości należy używać Mapkonkretnej implementacji i tak , jest to najlepsza praktyka.

To powiedziawszy, jest to dziwnie specyficzna sytuacja, w której wdrożenie Mapfaktycznie ma znaczenie. Nie będzie to prawdą dla 99,9% przypadków w twoim kodzie, kiedy używasz Map, a jednak jesteś, w tej 0,1% sytuacji. Sonar nie może tego wiedzieć, dlatego Sonar po prostu mówi ci, aby unikać używania konkretnej implementacji, ponieważ w większości przypadków byłoby to poprawne.

Argumentowałbym, że jeśli możesz uzasadnić użycie konkretnej implementacji, nie próbuj nakładać szminki na świnię. Potrzebujesz a LinkedHashMapnie Map.

To powiedziawszy, jeśli jesteś nowy w programowaniu i spotykasz się z tą odpowiedzią, nie sądzę, że pozwala to przeciwstawić się najlepszym praktykom, ponieważ tak nie jest. Ale gdy zamiana jednej implementacji na inną jest niedopuszczalna, jedyne, co możesz zrobić, to użyć tej konkretnej implementacji i być przeklętym przez Sonar.

Neil
źródło
1
Pragmatyczne podejście, które lubię.
Vidar S. Ramdal
20
Prawie całkowicie zgadzam się z odpowiedzią. Powiedziałbym tylko, że nie jesteś przeklęty przez Sonar. Zawsze możesz go skonfigurować tak, aby ignorował ten konkretny błąd / ostrzeżenie. Zobacz stackoverflow.com/questions/10971968/…
Vladimir Stokic
11
if you are new to programming and stumble upon this answer, don't think this allows you to go against best practice because it doesn't.- Dobra rada, jeśli istnieje coś takiego jak „najlepsza praktyka”. Lepsza rada: dowiedz się, jak podejmować właściwe decyzje. Postępuj zgodnie z praktyką, jeśli ma to sens, ale pozwól narzędziom i władzom kierować procesem myślenia, a nie dyktować.
Robert Harvey
13
Uwaga: kiedy sonar coś ci zgłosi, możesz to zamknąć jako „nie rozwiąże się” i zostaw notatkę z informacją, dlaczego tego nie zrobisz. Jako taki nie tylko sonar przestanie ci przeszkadzać, ale będziesz miał trop, dlaczego to zrobiłeś.
Walfrat
2
Myślę, że aspektem, który czyni to wyjątkiem od ogólnej zasady jest to, że LinkedHashMap ma umowę, która jest specyficzna dla tej implementacji i nie jest wyrażona w żadnym interfejsie. To nie jest zwykły przypadek. Zatem jedynym sposobem na wyrażenie zaufania do tej umowy jest użycie typu wdrożenia.
Dana
21

Walczysz z trzema rzeczami:

Pierwszą jest biblioteka kontenerów Java. Nic w jego taksonomii nie pozwala ci ustalić, czy klasa iteruje w przewidywalnym porządku. Nie ma IteratesInInsertedOrderMapinterfejsu, który mógłby zostać zaimplementowany LinkedHashMap, co uniemożliwia sprawdzenie typu (i użycie alternatywnych implementacji, które zachowują się w ten sam sposób). Prawdopodobnie jest to zgodne z projektem, ponieważ jego duch polega na tym, że naprawdę powinieneś być w stanie poradzić sobie z obiektami, które zachowują się jak abstrakcja Map.

Drugi to przekonanie, że to, co mówi twój liniowiec, musi być traktowane jak ewangelia i że ignorowanie wszystkiego, co mówi, jest złe. W przeciwieństwie do tego, co w dzisiejszych czasach uchodzi za dobrą praktykę, ostrzeżenia liniowe nie powinny stanowić przeszkody w dobrym nazywaniu kodu. Są monitami o uzasadnienie kodu, który napisałeś, i wykorzystują twoje doświadczenie i osąd, aby ustalić, czy ostrzeżenie jest uzasadnione. Nieuzasadnione ostrzeżenia powodują, że prawie każde narzędzie do analizy statycznej zapewnia mechanizm informujący, że sprawdziłeś kod, uważasz, że to, co robisz, jest w porządku i że nie powinni narzekać na to w przyszłości.

Po trzecie, i to jest prawdopodobnie jego główne znaczenie, LinkedHashMapmoże być niewłaściwym narzędziem do tego zadania. Mapy są przeznaczone do losowego, niezamówionego dostępu. Jeśli processData()po prostu iteruje się po rekordach w kolejności i nie musi znajdować innych rekordów według klucza, wymusza się konkretną implementację Mapwykonania zadania List. Z drugiej strony, jeśli potrzebujesz obu, LinkedHashMapjest to właściwe narzędzie, ponieważ wiadomo, że możesz robić to, co chcesz, i jest to więcej niż uzasadnione.

Blrfl
źródło
2
„LinkedHashMap może być niewłaściwym narzędziem dla zadania”. Tak, może. Kiedy mówię, że potrzebuję OrderedMap, równie dobrze mogę powiedzieć UniqueList. Tak długo, jak jest to jakaś kolekcja ze zdefiniowaną kolejnością iteracji, która zastępuje duplikaty przy wstawianiu.
Vidar S. Ramdal
2
@ VidarS.Ramdal Zapytanie do bazy danych byłoby idealnym miejscem do usunięcia duplikatów. Jeśli twoja baza danych nie jest w stanie tego zrobić, zawsze możesz tymczasowo przechowywać Settylko klucze podczas budowania listy jako sposób na ich wykrycie.
Blrfl
Och, widzę, że spowodowałem zamieszanie. Tak, wynik zapytania do bazy danych nie zawiera duplikatów. Ale processDatamodyfikuje mapę, zastępując niektóre wartości, wprowadzając nowe klucze / wartości. processDataMogłoby więc wprowadzić duplikaty, gdyby działało na czymś innym niż Map.
Vidar S. Ramdal
7
@ VidarS.Ramdal: Wygląda na to, że musisz napisać własny UniqueList(lub OrderedUniqueList) i użyć go. Jest to dość łatwe i sprawia, że ​​zamierzone użytkowanie jest jaśniejsze.
TMN
2
@TMN Tak, zacząłem myśleć w tym kierunku. Jeśli chcesz opublikować swoją sugestię jako odpowiedź, na pewno uzyska ona moje poparcie.
Vidar S. Ramdal
15

Jeśli wszystko, co dostajesz, LinkedHashMapto możliwość zastępowania duplikatów, ale tak naprawdę używasz go jako List, to sugeruję, aby lepiej zakomunikować to użycie z własną niestandardową Listimplementacją. Można oprzeć się na istniejących zbiorów klasy Java i po prostu zastąpić dowolny addi removemetod, aby zaktualizować swój sklep podkładową i śledzić klucza, aby zapewnić niepowtarzalność. Nadanie tej charakterystycznej nazwy, jak, ProcessingListpozwoli wyjaśnić, że argumenty przedstawione twojej processDatametodzie muszą być traktowane w określony sposób.

TMN
źródło
5
To i tak może być dobry pomysł. Do cholery, możesz nawet mieć plik jednowierszowy, który tworzy się ProcessingListjako alias LinkedHashMap- zawsze możesz zdecydować o zastąpieniu go innym czymś później, o ile nie zmienisz publicznego interfejsu.
CompuChip
11

Słyszę, jak mówisz: „Mam jedną część mojego systemu, która produkuje LinkedHashMap, a w innej części mojego systemu muszę akceptować tylko obiekty LinkedHashMap, które zostały wytworzone przez pierwszą część, ponieważ te wytworzone w innym procesie wygrały” t działa poprawnie. ”

To sprawia, że ​​myślę, że problem polega na tym, że próbujesz użyć LinkedHashMap, ponieważ w większości pasuje on do poszukiwanych danych, ale w rzeczywistości nie można go zastąpić żadną inną instancją niż te, które tworzysz. To, co naprawdę chcesz zrobić, to stworzyć własny interfejs / klasę, którą tworzy twoja pierwsza część, a druga część zużywa. Może owinąć „prawdziwą” LinkedHashMap i udostępnić narzędzie do pobierania map lub implementować interfejs mapy.

To trochę różni się od odpowiedzi CandiedOrange, ponieważ zalecałbym enkapsulację prawdziwej mapy (i delegowanie wywołań do niej w razie potrzeby) zamiast jej rozszerzania. Czasami jest to jedna z tych świętych wojen w stylu, ale na pewno brzmi dla mnie, że nie jest to „Mapa z dodatkowymi rzeczami”, ale „Moja torba z przydatnymi informacjami o stanie, którą wewnętrznie mogę reprezentować z Mapą”.

Gdybyście mieli dwie zmienne, które musielibyście przekazać w ten sposób, prawdopodobnie stworzylibyście dla niej klasę, nie zastanawiając się nad tym dużo. Ale czasem warto mieć klasę, nawet jeśli jest to tylko jedna zmienna składowa, tylko dlatego, że jest to logicznie to samo, a nie „wartość”, ale „wynik mojej operacji, z którą muszę zrobić później”.


źródło
I jakby tego myślenia - Byłem tam :) MyBagOfUsefulInformationmusiałby metodę (lub konstruktora), aby go zapełnić: MyBagOfUsefulInformation.populate(SomeType data). Ale datamusiałby to być wynik posortowanego zapytania. Co by SomeTypebyło, gdyby nie LinkedHashMap? Nie jestem pewien, czy uda mi się przełamać ten Catch 22.
Vidar S. Ramdal
Dlaczego nie może MyBagOfUsefulInformationzostać utworzony przez DAO lub cokolwiek generującego dane w twoim systemie? Dlaczego w ogóle musisz udostępniać mapę pod spodem reszcie kodu poza producentem i konsumentem torby?
W zależności od architektury możesz użyć konstruktora prywatnego / chronionego / zawierającego tylko pakiet, aby wymusić utworzenie obiektu tylko przez producenta, którego chcesz. Lub może po prostu trzeba to zrobić jako konwencję, aby można ją było utworzyć tylko przez odpowiednią „fabrykę”.
Tak, skończyło się na zrobieniu czegoś nieco podobnego, przekazując MyBagOfUsefulInformationjako parametr metodę DAO: softwareengineering.stackexchange.com/a/360079/52573
Vidar S. Ramdal
4

LinkedHashMap to jedyna mapa Java, która ma funkcję kolejności wstawiania, której szukasz. Dlatego odrzucenie zasady inwersji zależności jest kuszące, a może nawet praktyczne. Najpierw jednak zastanów się, co trzeba zrobić, aby to zrobić. Oto, o co proszą SOLID .

Uwaga: zastąp nazwę nazwą Ramdalopisową, która informuje, że konsument tego interfejsu jest właścicielem tego interfejsu. Co sprawia, że ​​to organ decyduje, czy kolejność wstawiania jest ważna. Jeśli po prostu to nazwiesz InsertionOrderMap, naprawdę nie rozumiesz sensu.

public interface Ramdal {
    //ISP asks for just the methods that processData() actually uses.
    ...
}

public class RamdalLinkedHashMap extends LinkedHashMap implements Ramdal{} 

Ramdal<Key, Value> ramdal = new RamdalLinkedHashMap<>();

ramdal.put(key1, value1);
ramdal.put(key2, value2);

processData(ramdal);

Czy to duży projekt z przodu? Może zależy to od tego, jak prawdopodobne jest, że kiedykolwiek będziesz potrzebować implementacji LinkedHashMap. Ale jeśli nie stosujesz DIP tylko dlatego, że byłby to ogromny ból, nie sądzę, aby płyta kotła była bardziej bolesna niż ta. Jest to wzorzec, którego używam, gdy chcę, aby kod nietykalny zaimplementował interfejs, którego nie ma. Najbardziej bolesne jest myślenie o dobrych imionach.

candied_orange
źródło
2
Lubię nazywanie!
Vidar S. Ramdal
1

Dzięki za wiele dobrych sugestii i jedzenie do namysłu.

Ostatecznie rozszerzyłem tworzenie nowej klasy mapy, tworząc processDatametodę instancji:

class DataMap extends LinkedHashMap<Key, Value> {

   processData();

}

Następnie dokonałem refaktoryzacji metody DAO, aby nie zwracała mapy, ale zamiast tego przyjmuje targetmapę jako parametr:

public void fetchData(Map<Key, Value> target) {
  ...
  // for each result row
  target.put(key, value);
}

Więc wypełnianie DataMapi przetwarzanie danych jest teraz procesem dwuetapowym, co jest w porządku, ponieważ istnieją inne zmienne, które są częścią algorytmu, który pochodzi z innych miejsc.

public DataMap fetchDataMap() {
  var dataMap = new DataMap();
  dao.fetchData(dataMap);
  return dataMap;
}

To pozwala mojej implementacji mapy kontrolować sposób wstawiania do niej wpisów i ukrywa wymagania dotyczące zamawiania - jest to teraz szczegół implementacji DataMap.

Vidar S. Ramdal
źródło
0

Jeśli chcesz poinformować, że użyta struktura danych istnieje z jakiegoś powodu, dodaj komentarz powyżej podpisu metody. Jeśli inny programista w przyszłości natrafi na ten wiersz kodu i zauważy ostrzeżenie dotyczące narzędzia, może również zauważyć komentarz i powstrzymać się od „naprawienia” problemu. Jeśli nie ma komentarza, nic nie powstrzyma ich przed zmianą podpisu.

Moim zdaniem tłumienie ostrzeżeń jest gorsze niż komentowanie, ponieważ samo tłumienie nie podaje powodu, dla którego ostrzeżenie zostało zniesione. Kombinacja wyłączenia ostrzeżenia i komentarza również będzie w porządku.

Kapol
źródło
0

Pozwól mi więc spróbować zrozumieć twój kontekst tutaj:

... kolejność wstawiania ma znaczenie ... Sortowanie mapy byłoby ciężką operacją ...

... wynik zapytania jest już posortowany tak, jak chcę

Teraz to, co już robisz:

Pobieram zestaw krotek z bazy danych i umieszczam na mapie ...

A oto twój obecny kod:

public void processData(LinkedHashMap<Key, Value> data) {...}

Moją sugestią jest wykonanie następujących czynności:

  • Użyj iniekcji zależności i wstrzyknij MyTupleRepository do metody przetwarzania (MyTupleRepository to interfejs implementowany przez obiekty, które pobierają twoje krotki, zwykle z DB);
  • wewnętrznie do metody przetwarzania, umieść dane z repozytorium (inaczej DB, który już zwraca zamówione dane) w konkretnej kolekcji LinkedHashMap, ponieważ jest to wewnętrzny szczegół algorytmu przetwarzania (ponieważ zależy to od sposobu ułożenia danych w strukturze danych );
  • Zauważ, że jest to właściwie to, co już robisz, ale w tym przypadku byłoby to zrobione w ramach metody przetwarzania. Twoje repozytorium jest tworzone w innym miejscu (masz już klasę, która zwraca dane, w tym przykładzie jest to repozytorium)

Przykład kodu

public interface MyTupleRepository {
    Collection<MyTuple> GetAll();
}

//Concrete implementation of data access object, that retrieves 
//your tuples from DB; this data is already ordered by the query
public class DbMyTupleRepository implements MyTupleRepository { }

//Injects some abstraction of repository into the processing method,
//but make it clear that some exception might be thrown if data is not
//arranged in some specific way you need
public void processData(MyTupleRepository tupleRepo) throws DataNotOrderedException {

    LinkedHashMap<Key, Value> data = new LinkedHashMap<Key, Value>();

    //Represents the query to DB, that already returns ordered data
    Collection<MyTuple> myTuples = tupleRepo.GetAll();

    //Optional: this would throw some exception if data is not ordered 
    Validate(myTuples);

    for (MyTupleData t : myTuples) {
        data.put(t.key, t.value);
    }

    //Perform the processing using LinkedHashMap...
    ...
}

Wydaje mi się, że pozbyłoby się to ostrzeżenia Sonaru, a także określił w podpisie specyficzny układ danych wymaganych przez metodę przetwarzania.

Emerson Cardoso
źródło
Hmm, ale w jaki sposób utworzono by repozytorium? Czy to nie przeniesie problemu gdzie indziej (gdzie MyTupleRepositoryzostanie stworzony?)
Vidar S. Ramdal
Myślę, że napotkam ten sam problem, co w przypadku odpowiedzi Petera Coopera .
Vidar S. Ramdal,
Moja sugestia dotyczy zastosowania zasady wstrzykiwania zależności; w tym przykładzie; MyTupleRepository to interfejs, który określa możliwość pobierania wspomnianych krotek (które pytają DB). Tutaj wstrzykujesz ten obiekt do metody przetwarzania. Masz już klasę, która zwraca dane; to tylko abstraktuje go w interfejsie i wstrzykujesz obiekt do metody „processData”, która wewnętrznie korzysta z LinkedHashMap, ponieważ jest to nieodłącznie część przetwarzania.
Emerson Cardoso,
Zredagowałem swoją odpowiedź, starając się wyjaśnić, co sugeruję.
Emerson Cardoso,
-1

To pytanie jest w rzeczywistości wiązką problemów z połączonym modelem danych. Musisz zacząć je rozplątywać pojedynczo. Bardziej naturalne, intuicyjne rozwiązania znikną, gdy spróbujesz uprościć każdy element układanki.

Problem 1: Nie możesz polegać na zamówieniu DB

Twoje opisy sortowania danych nie są jasne.

  • Największym potencjalnym problemem jest to, że nie określasz jawnego sortowania w bazie danych za pomocą ORDER BYklauzuli. Jeśli nie jesteś, ponieważ wydaje się to zbyt drogie, twój program ma błąd . Bazy danych mogą zwracać wyniki w dowolnej kolejności, jeśli nie zostanie określona; nie możesz polegać na tym, że przypadkowo zwraca dane w kolejności tylko dlatego, że uruchomiłeś zapytanie kilka razy i tak to wygląda. Kolejność może ulec zmianie, ponieważ wiersze są przestawiane na dysku lub niektóre są usuwane, a nowe zajmują miejsce lub dodawany jest indeks. Państwo musi określić ORDER BYklauzulę jakiegoś rodzaju. Prędkość jest bezwartościowa bez poprawności.
  • Nie jest również jasne, co rozumiesz przez znaczenie kolejności wstawiania. Jeśli mówisz o samej bazie danych, musisz mieć kolumnę, która faktycznie to śledzi, i musi być uwzględniona w ORDER BYklauzuli. W przeciwnym razie masz błędy. Jeśli taka kolumna jeszcze nie istnieje, musisz ją dodać. Typowe opcje dla takich kolumn to kolumna ze znacznikiem czasu wstawiania lub klucz automatycznego zwiększania. Klucz automatycznego zwiększania jest bardziej niezawodny.

Problem 2: Wydajne sortowanie w pamięci

Po upewnieniu się, że gwarantowane jest zwracanie danych w oczekiwanej kolejności, możesz wykorzystać ten fakt, aby sortowanie w pamięci było znacznie wydajniejsze. Wystarczy dodać kolumnę row_number()lubdense_rank() (lub odpowiednik bazy danych) do zestawu wyników zapytania. Teraz każdy wiersz ma indeks , który da ci bezpośrednie wskazanie, jaka powinna być kolejność, i możesz sortować według tego trywialnie w pamięci. Upewnij się tylko, że nadasz indeksowi znaczącą nazwę (np sortedBySomethingIndex.).

Altówka. Teraz nie musisz już polegać na kolejności zestawów wyników bazy danych.

Problem 3: Czy w ogóle potrzebujesz tego przetwarzania w kodzie?

SQL jest naprawdę bardzo wydajny. To niesamowity deklaratywny język, który pozwala na wiele przekształceń i agregacji danych. Większość DB obsługuje obecnie nawet operacje między wierszami. Nazywa się je funkcjami okna lub analitycznymi:

Czy w ogóle potrzebujesz wciągnąć swoje dane do pamięci? Czy możesz wykonać całą pracę w zapytaniu SQL, używając funkcji okna? Jeśli możesz wykonać całą (a może nawet znaczącą część) pracę w DB, to fantastycznie! Twój problem z kodem zniknął (lub stał się o wiele prostszy)!

Problem 4: Co robisz data?

Zakładając, że nie możesz zrobić tego wszystkiego w DB, pozwól mi to wyjaśnić. Bierzesz dane jako mapę (na którą składają się rzeczy, których nie chcesz sortować), a następnie iterujesz je w kolejności wstawiania i modyfikujesz mapę w miejscu, zastępując wartość niektórych kluczy i dodając nowe?

Przepraszam, ale co do cholery?

Dzwoniący nie powinni się o to martwić . System, który stworzyłeś, jest wyjątkowo delikatny. Wystarczy jeden głupi błąd (może nawet popełniony przez ciebie, tak jak wszyscy to zrobiliśmy), aby wprowadzić jedną małą złą zmianę, a cała sprawa zapada się jak talia kart.

Oto może lepszy pomysł:

  • Niech twoja funkcja zaakceptuje a List.
  • Istnieje kilka sposobów rozwiązania problemu z zamówieniem.
    1. Zastosuj szybko Fast. Zgłaszaj błąd, jeśli lista nie jest w kolejności wymaganej przez funkcję. (Uwaga: Możesz użyć indeksu sortowania z Problemu 2, aby stwierdzić, czy jest).
    2. Utwórz samodzielnie posortowaną kopię (ponownie, korzystając z indeksu z problemu 2).
    3. Wymyśl sposób na zbudowanie samej mapy w kolejności.
  • Zbuduj potrzebną mapę wewnętrznie dla funkcji, aby osoba dzwoniąca nie musiała się tym przejmować.
  • Teraz powtarzaj wszystko, co reprezentujesz w porządku, i rób to, co musisz.
  • Zwróć mapę lub przekształć ją w odpowiednią wartość zwracaną

Możliwą odmianą może być zbudowanie posortowanej reprezentacji, a następnie utworzenie mapy klucza do indeksu . Umożliwi to zmodyfikowanie posortowanej kopii w miejscu, bez przypadkowego tworzenia duplikatów.

A może ma to bardziej sens: pozbyć się dataparametru i processDatafaktycznie pobrać własne dane. Następnie możesz udokumentować, że to robisz, ponieważ ma bardzo specyficzne wymagania dotyczące sposobu pobierania danych. Innymi słowy, spraw, aby funkcja była właścicielem całego procesu, a nie tylko jednego jego fragmentu; wzajemne zależności są zbyt silne, aby podzielić logikę na mniejsze części. (Zmień nazwę funkcji w tym procesie.)

Może to nie zadziała w twojej sytuacji. Nie wiem bez pełnych szczegółów problemu. Ale znam kruchy i mylący projekt, kiedy go słyszę.

Podsumowanie

Myślę, że problemem tutaj jest to, że diabeł tkwi w szczegółach. Kiedy zaczynam mieć takie kłopoty, zwykle dzieje się tak dlatego, że mam nieodpowiednią reprezentację moich danych dla problemu, który próbuję rozwiązać. Najlepszym rozwiązaniem jest znalezienie lepszej reprezentacji , a wtedy mój problem staje się prosty (może nie łatwy, ale bezpośredni) do rozwiązania.

Znajdź kogoś, kto osiągnie ten punkt: Twoim zadaniem jest zredukowanie problemu do zestawu prostych, prostych. Następnie możesz zbudować solidny, intuicyjny kod. Porozmawiaj z nimi. Dobry kod i dobry design sprawiają, że myślisz, że każdy idiota mógł je wymyślić, ponieważ są one proste. Może jest jakiś starszy programista, który ma sposób myślenia, z którym możesz porozmawiać.

jpmc26
źródło
„Co masz na myśli mówiąc, że nie ma naturalnego porządku, ale liczy się kolejność wstawiania? Czy mówisz, że ma to znaczenie, w jakiej kolejności dane zostały wstawione do tabeli DB, ale nie masz kolumny, która wskazywałaby, w jakiej kolejności wstawiono rzeczy?” - pytanie brzmi: „Sortowanie mapy byłoby ciężką operacją, więc chcę tego uniknąć, biorąc pod uwagę, że wynik zapytania jest już posortowany”. To wyraźnie oznacza, że nie jest calculatable określony porządek danych, ponieważ w przeciwnym razie sortowania go byłoby niemożliwe, a nie ciężki, ale że określona kolejność różni się od naturalnego porządku kluczy.
Jules
2
Innymi słowy, OP pracuje nad wynikami podobnymi do zapytania select key, value from table where ... order by othercolumni musi zachować kolejność przetwarzania. Kolejność wstawiania oni powołując się na to kolejność wkładania ich mapy , określonej według kolejności stosowanej w ich zapytania, a nie kolejności wstawiania do bazy danych . Jest to oczywiste, ich wykorzystania LinkedHashMap, który jest strukturą danych, która ma cechy zarówno o Mapio Listpar klucz-wartość.
Jules
@Jules, posprzątam trochę tę sekcję, dzięki. (Właściwie pamiętałem, że to czytałem, ale kiedy sprawdzałem różne rzeczy podczas pisania pytania, nie mogłem go znaleźć. Lol. Wpadłem też w chwasty.) Ale pytanie nie jest jasne, co robią z DB zapytanie i czy mają jawne sortowanie, czy nie. Mówią też, że „kolejność wstawiania się ma znaczenie”. Chodzi o to, że nawet jeśli sortowanie jest ciężkie, nie możesz polegać na DB, aby magicznie uporządkować rzeczy poprawnie, jeśli nie powiesz tego wprost. A jeśli to robi w PB, a następnie można użyć „Index”, aby to wydajny w kodzie.
jpmc26
* pisząc odpowiedź (Chyba powinienem już iść spać.)
jpmc26
Tak, @Jules ma rację. W zapytaniu znajduje się order byklauzula, ale nie jest ona trywialna ( nie tylko order by column), więc chcę uniknąć ponownego sortowania w Javie. Chociaż SQL jest potężny (a mówimy tutaj o bazie danych Oracle 11g), charakter processDataalgorytmu znacznie ułatwia wyrażanie w Javie. I tak, „kolejność wstawiania” oznacza „ kolejność wstawiania mapy ”, tj. Kolejność wyników zapytania.
Vidar S. Ramdal,