4 Stimmen

Data.Map verwenden oder nicht verwenden

Ich arbeite derzeit an einer Haskell-API. Letztere bietet einige Funktionen, die derzeit eine Liste der Listen als Eingabe, d.h. [(String,[(String, Double)])] .

Zur Veranschaulichung sehen Sie hier ein Beispiel für die Liste der Listen oben erwähnt:

[
    ("A",   [
                ("I1", 1),
                ("I2", 2),
            ]
    ),
    ("B",   [
                ("I1", 3),
            ]
    )
]

Ich habe einige privat Hilfsfunktionen. Eine Hilfsfunktion sucht nach bestimmten Einträgen in dieser Liste ( Data.List.find = O(n) ); eine weitere Funktion führt Schnittmengen aus; und eine weitere Funktion wandelt die oben dargestellte Liste in die folgende um:

[
    ("I1",  [
                ("A", 1),
                ("B", 3),
            ]
    ),
    ("I2",  [
                ("A", 2),
            ]
    )
]

Die Funktion, die die Transformation durchführt, verwendet Data.Map da es einige Funktionen bietet, die diesen Prozess sehr vereinfachen, wie Data.Map.unionWith y Data.Map.insertWith . Nun, da die Transformationsfunktion die Data.Map.fromList y Data.Map.toList dachte ich, es wäre schön, eine Karte der Karten anstelle einer Liste der Listen von Anfang an. Also änderte ich meine Beispieleingabe, um sie an die Karte der Karten Anforderung.

Zur Veranschaulichung hier noch einmal die Liste von oben als Karte der Karten :

Map.fromList [
    ("A",   Map.fromList [
                ("I1", 1),
                ("I2", 2),
            ]
    ),
    ("B",   Map.fromList [
                ("I1", 3),
            ]
    )
]

Dank dieses Schrittes hat mein Code ein paar Zeilen verloren, und dank der Data.Map.lookup Die Suche nach dem Gewünschten dauert jetzt nur noch O(log n) Zeit.

Trotzdem frage ich mich gerade, ob das wirklich eine gute Lösung ist? Ist eine Karte der Karten der richtige Weg? Oder sollte die Transformationsfunktion mit Data.Map.fromList y Data.Map.toList und lassen Sie den Rest mit Liste der Listen ? Oder besser noch, gibt es eine Datenstruktur, die für diese Art von Arbeit besser geeignet ist?

Ich bin sehr gespannt auf Ihre Antworten.

1 Stimmen

Sind Ihre Suchvorgänge tatsächlich schneller geworden (in Wanduhrzeit), oder haben Sie die algorithmische Komplexität verbessert? Die algorithmische Komplexität ist zwar eine wichtige Überlegung, aber es gibt noch andere Überlegungen. Wenn Sie nur wenige Elemente haben (vielleicht <10?), ist die Liste der Listen wahrscheinlich am effizientesten.

0 Stimmen

John: Danke für deinen Beitrag. Ich habe verwendet Data.List.find um nach einem Element zu suchen. Da es sich um eine Empfehlungs-API handelt, sollte sie in der Lage sein, eine große Menge an Daten zu verarbeiten.

0 Stimmen

John: Beim erneuten Lesen meines vorherigen Kommentars ist mir aufgefallen, dass ich nicht auf Ihre erste Frage geantwortet habe. Das tut mir leid. Ich habe die algorithmische Komplexität verbessert, da Data.List.find nimmt O(n) Zeit, und ich ersetzte sie durch Data.Map.lookup die in O(log n) tiempo.

4voto

rampion Punkte 84270

Die Initialisierung der Map-of-Maps dauert nur noch O(n) .

Betrachten Sie zunächst die Liste der Listen.

Nehmen wir an, die äußere Liste ist [ a 1 , a 2 , ..., a p ], und jedes innere Element ist ein j \= ( l j , [ b 0 , b 1 , ..., b q j ]). Dann dauert die Konstruktion der Liste der Listen O(n = ∑) j=1 p q j ).

Die Initialisierung einer inneren Karte erfordert m j . = O(q j ). Die Initialisierung der Map-of-Maps dauert O(∑ j=1 p m j ) = O(n).

0 Stimmen

Rampion: +1, und danke für Ihre ausgezeichnete Antwort. In diesem Fall kann ich weiter arbeiten mit Data.Map da die Initialisierung der beiden Strukturen in O(n) y Data.Map bietet die besser geeigneten Funktionen für meinen Anwendungsfall.

4voto

max Punkte 751

Das riecht nach Graphen und Kanten. Ein etwas anderer Ansatz, der funktionieren kann oder auch nicht, besteht darin, das Problem so zu überarbeiten, dass anstelle von [(String,[(String,Double)])] operieren Sie einfach mit 2 Tupeln von Zeichenketten. Dann haben Sie [((String, String), Double)] und die resultierende Karte ist vom Typ Data.Map.Map (String, String) Double .

Alternativ, wenn der Platz für String-Schlüssel begrenzt ist und daher effizient in Maschinen-Ints abgebildet werden kann, sollten Sie eine IntMap verwenden. Gleiche Semantik wie eine Karte, außer dass die Schlüssel Maschine ints (Int32 oder Int64) sein MUSS. Dies wird eine viel bessere Leistung haben.

2voto

Landei Punkte 53286

Natürlich hängt dies von Ihren tatsächlichen Daten ab, aber vielleicht könnten Sie stattdessen eine Multimap verwenden? Es gibt verschiedene Implementierungen (z.B. http://hackage.haskell.org/packages/archive/Holumbus-Distribution/0.0.1.1/doc/html/Holumbus-Data-MultiMap.html ), aber ich habe sie nicht ausprobiert.

0 Stimmen

Landei: +1, und danke auch für Ihren Hinweis. Ich werde mir das noch genauer ansehen. Von der Beschreibung her klingt es recht vielversprechend und für meinen Anwendungsfall gut geeignet.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X