Wie kommuniziert man, dass die Anzeigenreihenfolge in einer Karte von Bedeutung ist?

24

Ich hole eine Reihe von Tupeln aus der Datenbank und füge sie in eine Karte ein. Die Datenbankabfrage ist kostspielig.

Es gibt keine offensichtliche natürliche Reihenfolge der Elemente in der Karte, aber die Reihenfolge der Einfügungen ist dennoch wichtig. Das Sortieren der Karte wäre sehr aufwändig, daher möchte ich dies vermeiden, da das Abfrageergebnis bereits so sortiert ist, wie ich es möchte. Daher speichere ich das Abfrageergebnis einfach in a LinkedHashMapund gebe die Zuordnung von einer DAO-Methode zurück:

public LinkedHashMap<Key, Value> fetchData()

Ich habe eine Methode processData, die eine gewisse Verarbeitung auf der Karte durchführen sollte - einige Werte ändern, einige neue Schlüssel / Werte hinzufügen. Es ist definiert als

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

Mehrere Linters (Sonar usw.) beschweren sich jedoch, dass die Art der "Daten" eine Schnittstelle wie "Karte" sein sollte und nicht die Implementierung "LinkedHashMap" ( Squid S1319 ).
Also heißt es im Grunde, dass ich haben sollte

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

Aber ich möchte, dass die Methodensignatur sagt, dass die Kartenreihenfolge wichtig ist - es kommt auf den Algorithmus an processData-, damit meine Methode nicht nur eine zufällige Karte übergibt.

Ich möchte es nicht verwenden SortedMap, da es (aus dem Javadoc vonjava.util.SortedMap ) "nach der natürlichen Reihenfolge seiner Schlüssel oder von einem Komparator geordnet ist, der normalerweise zum Zeitpunkt der Erstellung der sortierten Karte bereitgestellt wird."

Meine Schlüssel haben keine natürliche Reihenfolge , und die Erstellung eines Komparators , um nichts zu tun, scheint ausführlich zu sein.

Und ich würde immer noch wollen, dass es eine Karte ist, putum doppelte Schlüssel usw. zu vermeiden. Wenn nicht, datahätte es eine sein können List<Map.Entry<Key, Value>>.

Wie sage ich also, dass meine Methode eine Karte haben möchte, die bereits sortiert ist ? Leider gibt es keine java.util.LinkedMapSchnittstelle, sonst hätte ich das benutzt.

Vidar S. Ramdal
quelle

Antworten:

56

Also benutze LinkedHashMap.

Ja , Sie sollten nach Möglichkeit Mapeine bestimmte Implementierung überschreiben. Ja , dies ist die beste Vorgehensweise.

Das heißt, dies ist eine seltsam spezifische Situation, in der die Umsetzung Maptatsächlich von Bedeutung ist. Dies gilt nicht für 99,9% der Fälle in Ihrem Code, in denen Sie Map0,1% verwenden , und dennoch sind Sie hier. Sonar kann dies nicht wissen und fordert Sie daher einfach auf, die Verwendung der spezifischen Implementierung zu vermeiden, da dies in den meisten Fällen korrekt wäre.

Ich würde argumentieren, dass, wenn Sie die Verwendung einer bestimmten Implementierung begründen können, Sie nicht versuchen sollten, einem Schwein Lippenstift zu geben. Du brauchst a LinkedHashMap, nicht a Map.

Das heißt, wenn Sie neu in der Programmierung sind und über diese Antwort stolpern, denken Sie nicht, dass dies es Ihnen ermöglicht, gegen die besten Praktiken zu verstoßen, weil dies nicht der Fall ist. Aber wenn das Ersetzen einer Implementierung durch eine andere nicht akzeptabel ist, können Sie nur diese spezielle Implementierung verwenden und für Sonar verdammt sein.

Neil
quelle
1
Pragmatischer Ansatz, den ich mag.
Vidar S. Ramdal
20
Ich stimme der Antwort fast vollständig zu. Ich würde nur sagen, dass Sie nicht Sonar verdammt sind. Sie können es jederzeit so konfigurieren, dass dieser bestimmte Fehler / diese Warnung ignoriert wird. Siehe 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.- Guter Rat, wenn es so etwas wie "Best Practice" gäbe. Besser beraten: Erfahren Sie, wie Sie die richtigen Entscheidungen treffen. Folgen Sie der Praxis, wenn es Sinn macht, aber lassen Sie Werkzeuge und Behörden Ihren Denkprozess leiten, nicht diktieren.
Robert Harvey
13
Hinweis: Wenn Sonar Ihnen etwas meldet, können Sie es als "Nicht gelöst" schließen und eine Notiz hinterlassen, warum Sie dies nicht tun. Als solches wird nicht nur das Sonar aufhören, Sie zu stören, sondern Sie werden einen Überblick darüber haben, warum Sie das getan haben.
Walfrat
2
Ich denke, der Aspekt, der dies zu einer Ausnahme vom allgemeinen Prinzip macht, ist, dass LinkedHashMap einen Vertrag hat, der spezifisch für diese Implementierung ist und in keiner Schnittstelle zum Ausdruck kommt. Dies ist nicht der übliche Fall. Die einzige Möglichkeit, das Vertrauen in diesen Vertrag zum Ausdruck zu bringen, ist die Verwendung des Implementierungstyps.
Dana
21

Du kämpfst gegen drei Dinge:

Erstens ist Java Container-Bibliothek. Nichts in seiner Taxonomie gibt Ihnen die Möglichkeit zu bestimmen, ob die Klasse in einer vorhersagbaren Reihenfolge iteriert oder nicht. Es gibt keine IteratesInInsertedOrderMapSchnittstelle, die implementiert werden könnte LinkedHashMap, wodurch die Typprüfung (und die Verwendung alternativer Implementierungen, die sich auf die gleiche Weise verhalten) unmöglich wird. Das ist wahrscheinlich so gewollt, weil der Geist davon ist, dass man wirklich in der Lage sein soll, mit Objekten umzugehen, die sich wie das Abstrakte verhalten Map.

Zweitens ist es eine Überzeugung, dass das, was deine Beschwörerin sagt, als Evangelium behandelt werden muss und dass es schlecht ist, alles zu ignorieren, was es sagt. Im Gegensatz zu dem, was heutzutage als bewährte Methode gilt, sollten Linter-Warnungen keine Barrieren für den Aufruf Ihres Codes darstellen. Sie werden aufgefordert, über den von Ihnen geschriebenen Code nachzudenken und anhand Ihrer Erfahrung und Ihres Urteils zu bestimmen, ob die Warnung gerechtfertigt ist oder nicht. Ungerechtfertigte Warnungen sind der Grund, warum fast jedes statische Analysetool einen Mechanismus bietet, mit dem Sie feststellen können, dass Sie den Code überprüft haben, Sie denken, was Sie tun, ist in Ordnung und sie sollten sich in Zukunft nicht darüber beschweren.

Drittens, und dies ist wahrscheinlich das Fleisch davon, LinkedHashMapkann das falsche Werkzeug für den Job sein. Karten sind für den zufälligen, nicht geordneten Zugriff vorgesehen. Wenn processData()Sie die Datensätze einfach der Reihe nach durchlaufen und keine anderen Datensätze nach Schlüssel suchen müssen, erzwingen Sie eine bestimmte Implementierung von Map, um die Aufgabe eines zu erledigen List. Auf der anderen Seite LinkedHashMapist es das richtige Werkzeug , wenn Sie beides benötigen, da es bekanntermaßen das tut, was Sie wollen, und Sie mehr als berechtigt sind, es zu fordern .

Blrfl
quelle
2
"LinkedHashMap ist möglicherweise das falsche Tool für den Job". Ja vielleicht. Wenn ich sage, ich brauche eine OrderedMap, könnte ich das genauso gut sagen UniqueList. Solange es sich um eine Sammlung mit einer definierten Iterationsreihenfolge handelt, werden beim Einfügen Duplikate überschrieben.
Vidar S. Ramdal
2
@ VidarS.Ramdal Die Datenbankabfrage wäre der ideale Ort, um die Duplikate auszusondern. Wenn dies in Ihrer Datenbank nicht möglich ist, können Sie Setbeim Erstellen der Liste immer nur eine temporäre Liste der Schlüssel erstellen, um sie zu erkennen.
Blrfl
Oh, wie ich sehe, habe ich Verwirrung gestiftet. Ja, das Datenbankabfrageergebnis enthält keine Duplikate. Aber processDataändert die Karte, einige Werte zu ersetzen, einige neue Schlüssel / Wert - Einführung. Könnte also processDataDuplikate einführen, wenn es auf etwas anderem als a operiert Map.
Vidar S. Ramdal
7
@ VidarS.Ramdal: Es hört sich so an, als müssten Sie Ihre eigenen UniqueList(oder OrderedUniqueList) schreiben und diese verwenden. Es ist ziemlich einfach und macht Ihren Verwendungszweck klarer.
TMN
2
@TMN Ja, ich habe angefangen, in diese Richtung zu denken. Wenn Sie Ihren Vorschlag als Antwort posten möchten, wird er mit Sicherheit meine Zustimmung finden.
Vidar S. Ramdal
15

Wenn Sie LinkedHashMapnur die Möglichkeit haben, Duplikate zu überschreiben, diese jedoch tatsächlich als verwenden List, ist es empfehlenswert, diese Verwendung mit Ihrer eigenen benutzerdefinierten ListImplementierung zu kommunizieren . Sie können es auf einem vorhandenen Java Sammlungen Klasse basieren und einfach jede außer Kraft setzen addund removeMethoden , um Ihre Sicherungsspeicher zu aktualisieren und den Überblick über die Taste halten , um sicherzustellen , Einzigartigkeit. Wenn Sie diesem Namen einen eindeutigen Namen ProcessingListgeben, wird deutlich, dass Argumente, die für Ihre processDataMethode verwendet werden, auf eine bestimmte Art und Weise behandelt werden müssen.

TMN
quelle
5
Dies kann sowieso eine gute Idee sein. Sie können sogar eine einzeilige Datei ProcessingListals Alias ​​für erstellen. LinkedHashMapSie können sie später jederzeit durch eine andere ersetzen, solange die öffentliche Schnittstelle intakt bleibt.
CompuChip
11

Ich höre Sie sagen: "Ich habe einen Teil meines Systems, der eine LinkedHashMap erstellt, und in einem anderen Teil meines Systems muss ich nur LinkedHashMap-Objekte akzeptieren, die im ersten Teil erstellt wurden, da diejenigen, die mit einem anderen Verfahren erstellt wurden, gewonnen wurden." funktioniert nicht richtig. "

Aus diesem Grund denke ich, dass das Problem hier darin besteht, dass Sie LinkedHashMap verwenden, da es hauptsächlich für die gesuchten Daten geeignet ist. Tatsächlich kann es jedoch nicht durch eine andere Instanz als die von Ihnen erstellten ersetzt werden. Eigentlich möchten Sie eine eigene Schnittstelle / Klasse erstellen, die Ihr erster Teil erstellt und Ihr zweiter Teil verwendet. Es kann die "echte" LinkedHashMap umschließen und einen Map-Getter bereitstellen oder die Map-Schnittstelle implementieren.

Dies unterscheidet sich ein wenig von der Antwort von CandiedOrange, da ich empfehlen würde, die echte Map zu kapseln (und Aufrufe an sie nach Bedarf zu delegieren), anstatt sie zu erweitern. Es ist manchmal einer dieser heiligen Kriege, aber es klingt für mich sicher, dass es nicht "Eine Karte mit ein paar zusätzlichen Dingen" ist, sondern "Meine Tasche mit nützlichen Zustandsinformationen, die ich intern mit einer Karte repräsentieren kann".

Wenn Sie zwei Variablen hätten, die Sie auf diese Weise weitergeben müssten, hätten Sie wahrscheinlich eine Klasse dafür erstellt, ohne viel darüber nachzudenken. Aber manchmal ist es nützlich, eine Klasse zu haben, auch wenn es sich nur um eine Elementvariable handelt, nur weil es logischerweise dasselbe ist, kein "Wert", sondern "das Ergebnis meiner Operation, mit der ich später etwas anfangen muss".


quelle
Ich mag dieses Denken - ich bin dort gewesen :) MyBagOfUsefulInformationmüßte eine Methode (oder Konstruktor) , um es zu füllen: MyBagOfUsefulInformation.populate(SomeType data). Müsste dataaber das sortierte Abfrageergebnis sein. Was wäre SomeType, wenn nicht LinkedHashMap? Ich bin mir nicht sicher, ob ich diesen Fang 22 brechen kann.
Vidar S. Ramdal,
Warum kann MyBagOfUsefulInformationdas DAO keine Daten erstellen oder was auch immer erzeugt die Daten in Ihrem System? Warum müssen Sie die zugrunde liegende Karte außerhalb des Herstellers und Verbrauchers der Tasche für den Rest Ihres Codes verfügbar machen?
Abhängig von Ihrer Architektur können Sie möglicherweise einen privaten / protected / package-only-Konstruktor verwenden, um zu erzwingen, dass das Objekt nur von dem Produzenten erstellt werden kann, den Sie möchten. Oder Sie müssen es nur als Konvention tun, dass es nur von der richtigen "Fabrik" erstellt werden kann.
Ja, am Ende habe ich etwas Ähnliches getan, indem ich MyBagOfUsefulInformationals Parameter an die DAO-Methode übergeben habe: softwareengineering.stackexchange.com/a/360079/52573
Vidar S. Ramdal
4

LinkedHashMap ist die einzige Java-Karte, die die von Ihnen gesuchte Funktion für die Reihenfolge der Einfügungen enthält. Das Prinzip der Abhängigkeitsinversion zu verwerfen ist also verlockend und vielleicht sogar praktisch. Überlegen Sie sich jedoch zunächst, was erforderlich ist, um dem zu folgen. Hier ist, was SOLID Sie bitten würde, zu tun.

Anmerkung: Ersetzen Sie den Namen Ramdaldurch einen beschreibenden Namen, der angibt, dass der Benutzer dieser Schnittstelle der Eigentümer dieser Schnittstelle ist. Das macht es zu der Autorität, die entscheidet, ob die Einfügereihenfolge wichtig ist. Wenn Sie dies nur nennen, haben InsertionOrderMapSie den Punkt wirklich verpasst.

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

Ist das ein großes Design vorne? Vielleicht hängt es davon ab, wie wahrscheinlich es ist, dass Sie jemals eine Implementierung benötigen LinkedHashMap. Aber wenn Sie DIP nicht nur verfolgen, weil es sehr schmerzhaft wäre, denke ich nicht, dass die Kesselplatte schmerzhafter ist als diese. Dies ist das Muster, das ich verwende, wenn ich möchte, dass unberührbarer Code eine Schnittstelle implementiert, die es nicht tut. Das Schmerzlichste ist wirklich, an gute Namen zu denken.

kandierte_orange
quelle
2
Ich mag die Namensgebung!
Vidar S. Ramdal
1

Vielen Dank für viele gute Anregungen und Denkanstöße.

Am Ende habe ich die Erstellung einer neuen Map-Klasse erweitert und processDataeine Instanzmethode erstellt:

class DataMap extends LinkedHashMap<Key, Value> {

   processData();

}

Dann habe ich die DAO-Methode überarbeitet, sodass sie keine Karte zurückgibt, sondern stattdessen eine targetKarte als Parameter verwendet:

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

Das Auffüllen DataMapund Verarbeiten der Daten ist nun ein zweistufiger Prozess, der in Ordnung ist, da es einige andere Variablen gibt, die Teil des Algorithmus sind und von anderen Stellen stammen.

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

Auf diese Weise kann meine Map-Implementierung steuern, wie Einträge in sie eingefügt werden, und die Bestellanforderung wird ausgeblendet - sie ist jetzt ein Implementierungsdetail von DataMap.

Vidar S. Ramdal
quelle
0

Wenn Sie mitteilen möchten, dass die von Ihnen verwendete Datenstruktur aus einem bestimmten Grund vorhanden ist, fügen Sie einen Kommentar über der Signatur der Methode ein. Wenn ein anderer Entwickler in Zukunft auf diese Codezeile stößt und eine Toolwarnung bemerkt, bemerkt er möglicherweise auch den Kommentar und "behebt" das Problem nicht mehr. Wenn es keinen Kommentar gibt, hindert sie nichts daran, die Signatur zu ändern.

Das Unterdrücken von Warnungen ist meiner Meinung nach schlechter als das Kommentieren, da die Unterdrückung selbst nicht den Grund angibt, warum die Warnung unterdrückt wurde. Eine Kombination aus Warnungsunterdrückung und Kommentar ist ebenfalls in Ordnung.

Kapol
quelle
0

Lassen Sie mich versuchen, Ihren Kontext hier zu verstehen:

... Einfügereihenfolge ist wichtig ... Das Sortieren der Karte wäre eine schwere Aufgabe ...

... das Abfrageergebnis ist bereits so sortiert, wie ich es möchte

Nun, was Sie gerade tun:

Ich hole eine Reihe von Tupeln aus der Datenbank und füge sie in eine Karte ein ...

Und hier ist dein aktueller Code:

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

Mein Vorschlag ist, Folgendes zu tun:

  • Verwenden Sie die Abhängigkeitsinjektion und injizieren Sie MyTupleRepository in die Verarbeitungsmethode (MyTupleRepository ist eine Schnittstelle, die von Objekten implementiert wird, die Ihre Tupelobjekte abrufen, normalerweise aus der Datenbank).
  • Fügen Sie intern zur Verarbeitungsmethode Daten aus dem Repository (auch bekannt als DB, die bereits bestellte Daten zurückgibt) in die bestimmte LinkedHashMap-Auflistung ein, da dies ein internes Detail des Verarbeitungsalgorithmus ist (da dies davon abhängt, wie die Daten in der Datenstruktur angeordnet sind) );
  • Beachten Sie, dass dies so ziemlich das ist, was Sie bereits tun, aber in diesem Fall würde dies innerhalb der Verarbeitungsmethode erfolgen. Ihr Repository wird an einer anderen Stelle instanziiert. (Sie haben bereits eine Klasse, die Daten zurückgibt. Dies ist das Repository in diesem Beispiel.)

Code-Beispiel

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

Ich vermute, dies würde die Sonar-Warnung beseitigen und auch das für die Verarbeitungsmethode erforderliche signaturspezifische Layout der Daten festlegen.

Emerson Cardoso
quelle
Hmm, aber wie würde das Repository instanziiert? Wäre dies nicht einfach eine Verlagerung des Problems an einen anderen Ort ( MyTupleRepository
dorthin
Ich denke, ich werde auf dasselbe Problem stoßen wie bei Peter Coopers Antwort .
Vidar S. Ramdal
Mein Vorschlag beinhaltet die Anwendung des Abhängigkeitsinjektionsprinzips; in diesem Beispiel; MyTupleRepository ist eine Schnittstelle, die die Fähigkeit definiert, die von Ihnen erwähnten Tupel abzurufen (die die Datenbank abfragen). Hier injizieren Sie dieses Objekt in die Verarbeitungsmethode. Sie haben bereits eine Klasse, die die Daten zurückgibt. Dies abstrahiert es nur in einer Schnittstelle, und Sie injizieren das Objekt in die 'processData'-Methode, die intern die LinkedHashMap verwendet, da diese an sich Teil der Verarbeitung ist.
Emerson Cardoso
Ich habe meine Antwort bearbeitet und versucht, klarer zu sagen, was ich vorschlage.
Emerson Cardoso
-1

Diese Frage ist eigentlich eine Reihe von Problemen mit Ihrem Datenmodell, die in einem zusammengefasst sind. Sie müssen sie nacheinander entwirren. Natürlichere, intuitivere Lösungen fallen heraus, wenn Sie versuchen, jedes Teil des Puzzles zu vereinfachen.

Problem 1: Sie können sich nicht auf DB Order verlassen

Ihre Beschreibungen zum Sortieren Ihrer Daten sind nicht eindeutig.

  • Das größte potenzielle Problem besteht darin, dass Sie in Ihrer Datenbank keine explizite Sortierung über eine ORDER BYKlausel angeben. Wenn dies nicht der Fall ist, weil es zu teuer erscheint, hat Ihr Programm einen Fehler . Datenbanken können Ergebnisse in beliebiger Reihenfolge zurückgeben, wenn Sie keine angeben. Sie können sich nicht darauf verlassen, dass zufällig Daten in der Reihenfolge zurückgegeben werden, nur weil Sie die Abfrage einige Male ausgeführt haben und es so aussieht. Die Reihenfolge kann sich ändern, weil Zeilen auf der Festplatte neu angeordnet werden oder einige gelöscht werden und neue an ihre Stelle treten oder ein Index hinzugefügt wird. Sie müssen eine ORDER BYKlausel angeben . Geschwindigkeit ist wertlos ohne Richtigkeit.
  • Es ist auch nicht klar, was Sie unter Einfügereihenfolge verstehen. Wenn Sie über die Datenbank selbst sprechen, müssen Sie eine Spalte haben, die dies tatsächlich verfolgt, und sie muss in Ihrer ORDER BYKlausel enthalten sein. Ansonsten hast du Bugs. Wenn eine solche Spalte noch nicht existiert, müssen Sie eine hinzufügen. Typische Optionen für Spalten wie diese wären eine Einfügezeitstempelspalte oder ein automatisch inkrementierender Schlüssel. Der automatische Inkrementierungsschlüssel ist zuverlässiger.

Problem 2: Effizientes Sortieren im Speicher

Sobald Sie es sicherstellen , dass garantierte Daten in der Reihenfolge zurückkehren Sie erwarten, können Sie diese Tatsache nutzen , in Erinnerung zu machen Sorten viel effizienter. Fügen Sie der Ergebnismenge Ihrer Abfrage einfach eine row_number()oderdense_rank() -Spalte (oder das Äquivalent Ihrer Datenbank) hinzu. Jetzt hat jede Zeile einen Index , der Ihnen einen direkten Hinweis darauf gibt, wie die Reihenfolge lauten soll, und Sie können trivial danach sortieren. Stellen Sie einfach sicher, dass Sie dem Index einen aussagekräftigen Namen geben (wie sortedBySomethingIndex).

Viola. Jetzt müssen Sie nicht mehr auf die Reihenfolge der Datenbank-Ergebnismenge angewiesen sein.

Problem 3: Müssen Sie diese Verarbeitung überhaupt in Code ausführen?

SQL ist eigentlich sehr mächtig. Es ist eine erstaunliche deklarative Sprache, mit der Sie viele Transformationen und Aggregationen Ihrer Daten durchführen können. Die meisten DBs unterstützen heutzutage sogar zeilenübergreifende Operationen. Sie werden Fenster- oder Analysefunktionen genannt:

Haben Sie selbst müssen Ihre Daten in den Speicher so ziehen? Oder können Sie die gesamte Arbeit in der SQL-Abfrage mithilfe von Fensterfunktionen ausführen? Wenn Sie alle (oder nur einen wesentlichen Teil) der Arbeit in der DB erledigen können, fantastisch! Ihr Code-Problem verschwindet (oder wird viel einfacher)!

Problem 4: Was machst du damit data?

Angenommen, Sie können nicht alles in der DB erledigen, lassen Sie mich das klarstellen. Sie nehmen die Daten als Map (die von Dingen codiert wird, nach denen Sie nicht sortieren möchten), iterieren dann in der Einfügereihenfolge darüber und ändern die Map an Ort und Stelle, indem Sie den Wert einiger Keys ersetzen und hinzufügen neue?

Es tut mir leid, aber was zum Teufel?

Anrufer sollten sich darüber keine Sorgen machen müssen . Das von Ihnen erstellte System ist äußerst instabil. Es braucht nur einen blöden Fehler (vielleicht sogar von Ihnen selbst gemacht, wie wir es alle getan haben), um eine kleine falsche Änderung vorzunehmen, und das Ganze bricht zusammen wie ein Kartenspiel.

Hier ist vielleicht eine bessere Idee:

  • Lassen Sie Ihre Funktion a akzeptieren List.
  • Es gibt verschiedene Möglichkeiten, um das Bestellproblem zu lösen.
    1. Übernehmen Schnell fehlschlagen. Wirf einen Fehler, wenn die Liste nicht in der Reihenfolge ist, die die Funktion erfordert. (Hinweis: Anhand des Sortierindex aus Problem 2 können Sie feststellen, ob dies der Fall ist.)
    2. Erstellen Sie selbst eine sortierte Kopie (wieder mit dem Index aus Aufgabe 2).
    3. Finden Sie eine Möglichkeit, die Karte selbst in der richtigen Reihenfolge aufzubauen.
  • Erstellen Sie die Map, die Sie benötigen, intern für die Funktion, damit sich der Anrufer nicht darum kümmern muss.
  • Nun iterieren Sie über alles, was Sie in der Auftragsdarstellung haben, und tun, was Sie tun müssen.
  • Geben Sie die Karte zurück oder wandeln Sie sie in einen geeigneten Rückgabewert um

Eine mögliche Variante könnte darin bestehen, eine sortierte Darstellung zu erstellen und dann eine Zuordnung der Schlüssel zum Index zu erstellen . Auf diese Weise können Sie Ihre sortierte Kopie ändern, ohne versehentlich Duplikate zu erstellen.

Oder vielleicht ist dies sinnvoller: Befreien Sie sich von dem dataParameter und lassen Sie processDataseine eigenen Daten abrufen. Sie können dann dokumentieren, dass Sie dies tun, da es sehr spezielle Anforderungen an die Art und Weise gibt, in der die Daten abgerufen werden. Mit anderen Worten, machen Sie die Funktion zum Eigentümer des gesamten Prozesses, nicht nur eines Teils davon. Die gegenseitigen Abhängigkeiten sind zu stark, um die Logik in kleinere Abschnitte aufzuteilen. (Ändern Sie den Namen der Funktion im Prozess.)

Möglicherweise arbeiten diese nicht für Ihre Situation. Ich weiß es nicht ohne vollständige Details des Problems. Aber ich kenne ein fragiles und verwirrendes Design, wenn ich eines höre.

Zusammenfassung

Ich denke, das Problem hier ist letztendlich, dass der Teufel im Detail steckt. Wenn ich auf diese Weise auf Probleme stoße, habe ich normalerweise eine unangemessene Darstellung meiner Daten für das Problem, das ich tatsächlich zu lösen versuche. Die beste Lösung ist , eine bessere Darstellung zu finden , und dann wird mein Problem einfach (vielleicht nicht einfach, aber unkompliziert) zu lösen.

Finden Sie jemanden, der diesen Punkt versteht: Ihre Aufgabe ist es, Ihr Problem auf eine Reihe einfacher, unkomplizierter zu reduzieren. Dann können Sie robusten, intuitiven Code erstellen. Rede mit ihnen. Guter Code und gutes Design lassen Sie denken, dass jeder Idiot sie sich ausgedacht haben könnte, weil sie einfach und unkompliziert sind. Vielleicht gibt es einen erfahrenen Entwickler, mit dem Sie sich austauschen können.

jpmc26
quelle
"Was meinst du damit, dass es keine natürliche Reihenfolge gibt, aber die Reihenfolge der Einfügung ist wichtig? Wollen Sie damit sagen, dass es darauf ankommt, in welcher Reihenfolge die Daten in die DB-Tabelle eingefügt wurden, aber Sie haben keine Spalte, die Ihnen sagen kann, welche Reihenfolge Dinge eingefügt wurden?" - Die Frage lautet wie folgt: "Das Sortieren der Karte wäre eine schwere Operation, daher möchte ich dies vermeiden, da das Abfrageergebnis bereits sortiert ist." Anschaulich bedeutet dies , dass es ist eine berechenbare bestimmte Reihenfolge auf die Daten, weil es sonst Sortierung eher unmöglich wäre , als schwer, aber das definierte Reihenfolge unterscheidet mich von der natürlichen Ordnung der Schlüssel.
Jules
2
Mit anderen Worten, OP bearbeitet die Ergebnisse einer Abfrage wie folgt select key, value from table where ... order by othercolumnund muss die Reihenfolge bei ihrer Verarbeitung beibehalten. Die Einfügereihenfolge, auf die sie sich beziehen, ist die Einfügereihenfolge in ihrer Karte , definiert durch die in ihrer Abfrage verwendete Reihenfolge, nicht die Einfügereihenfolge in der Datenbank . Dies wird durch die Verwendung von verdeutlicht LinkedHashMap, einer Datenstruktur, die die Eigenschaften eines Mapund eines ListSchlüssel-Wert-Paares aufweist.
Jules
@Jules Ich werde diesen Abschnitt ein bisschen aufräumen, danke. (Ich erinnerte mich tatsächlich daran, dass ich das gelesen hatte, aber als ich die Dinge beim Schreiben der Frage überprüfte, konnte ich sie nicht finden. Lol. Ich bin auch im Unkraut.) Aber die Frage ist nicht klar, was sie mit der DB machen Abfrage und ob sie eine explizite Sortierung haben oder nicht. Sie sagen auch, dass "die Reihenfolge der Einfügungen von Bedeutung ist". Der Punkt ist, dass Sie sich auch bei starker Sortierung nicht darauf verlassen können, dass die Datenbank die Dinge magisch richtig anordnet, wenn Sie dies nicht explizit anweisen. Und wenn Sie sind es in der DB zu tun, dann können Sie einen „Index“ , um es in Code effizienter zu machen.
jpmc26
* Antwort schreiben (Ich denke, ich sollte bald ins Bett gehen.)
jpmc26
Ja, @Jules ist richtig. Es ist eine order byKlausel in der Abfrage, aber es ist nicht trivial ( nicht nur order by column), so dass ich die Sortierung in Java vermeiden will Neuimplementierung. Obwohl SQL ist mächtig (und wir sprechen von einem Oracle 11g - Datenbank hier), die Art des processDatamacht Algorithmus einfacher ist es viel in Java auszudrücken. Und ja, "Einfügereihenfolge" bedeutet " Karteneinfügereihenfolge ", dh Abfrageergebnisreihenfolge.
Vidar S. Ramdal