Eine Liste von Listen effizient in F # projizieren

8

Ich muss eine Liste von Listen projektieren, die alle Kombinationen mit jedem Element aus jeder Liste zurückgibt. Zum Beispiel:

%Vor%

Ich habe eine Funktion:

%Vor%

und ein Testfall:

%Vor%

Die Funktion ist jetzt ziemlich langsam, mit N = 10 dauert es mehr als 10 Sekunden. Außerdem denke ich, dass die Lösung unnatürlich ist, weil ich dieselbe Liste auf zwei verschiedene Arten zusammenbrechen muss. Irgendwelche Vorschläge, wie ich die Leistung und Lesbarkeit der Funktion verbessern kann?

    
pad 01.06.2011, 08:15
quelle

5 Antworten

15

Versuchen Sie zuallererst, die Listenverkettung (@) zu vermeiden, wann immer es möglich ist, da es O (N) statt O (1) vorangestellt ist.

Ich würde mit einem (relativ) einfach zu verfolgenden Plan anfangen, wie man das kartesische äußere Produkt von Listen berechnet.

  • Jedes Element der ersten Liste wird jeder Unterliste im kartesischen Produkt der verbleibenden Listen vorangestellt.
  • Kümmere dich um den Basisfall.

Erste Version:

%Vor%

Dies ist die direkte Übersetzung der obigen Sätze in den Code.

Beschleunige dies jetzt: Benutze Listenverkettungen und Karten statt Listenkompressen:

%Vor%

Dies kann noch schneller gemacht werden, indem die Listen auf Anfrage über eine Sequenz berechnet werden:

%Vor%

Diese letzte Form verwende ich selbst, da ich meistens nur die Ergebnisse durchlaufen muss, anstatt sie alle auf einmal zu haben.

Einige Benchmarks auf meinem Rechner: Testcode:

%Vor%

Ergebnisse in FSI:

%Vor%     
cfern 01.06.2011, 09:40
quelle
5

Diese Funktion ist Haskells Sequenz (obwohl sequence generischer ist). Übersetzen zu F #:

%Vor%

in interaktiv:

%Vor%

Allgemeine Idee: Vermeiden Sie explizite Rekursion zugunsten von Standard-Kombinatoren (Fold, Map etc.)

    
Ed'ka 01.06.2011 11:28
quelle
1

Sie Implementierung ist langsam wegen der @ (d. h. List concat) -Operation, die eine langsame Operation ist, und es wird mehrmals in rekursiver Weise ausgeführt. Der Grund dafür, dass @ langsam ist, besteht darin, dass List in der funktionalen Programmierung eine Verknüpfungsliste ist. Um eine Liste zu erstellen, müssen Sie zuerst bis zum Ende der Liste gehen (nacheinander Elemente durchlaufen) und dann eine weitere Liste anhängen.

Sehen Sie sich die vorgeschlagenen Referenzen in Kommentaren an. Ich hoffe, die werden dir helfen.

    
Ankur 01.06.2011 09:32
quelle
1

Hier ist eine Tail-rekursive Version. Es ist nicht so schnell wie einige der anderen Lösungen (nur 25% schneller als Ihre ursprüngliche Funktion), aber die Speichernutzung ist konstant, so dass es für extrem große Ergebnismengen funktioniert.

%Vor%     
Daniel 01.06.2011 15:50
quelle
0
%Vor%     
George 11.03.2015 20:55
quelle

Tags und Links