Lazy "n wähle k" in OCaml

8

Als Teil eines größeren Problems beim Aufzählen einer Menge muss ich eine OCaml-Funktion "choose" schreiben, die eine Liste aufnimmt und als Liste aller möglichen Sequenzen der Größe k aus Elementen dieser Liste ausgibt (ohne sich zu wiederholen) Sequenzen, die durch Permutation voneinander erhalten werden können). Die Reihenfolge in der Endliste ist nicht relevant.

Zum Beispiel

%Vor%

Irgendwelche Ideen?

Ich möchte die ganze Sache faul haben und eine faule Liste ausgeben, aber wenn Sie eine strikte Lösung haben, wird das auch sehr nützlich sein.

    
Surikator 19.10.2010, 14:18
quelle

3 Antworten

9

Hier ist eine strenge und suboptimale Version. Ich hoffe es ist klar. Sie vermeidet Duplikate, indem angenommen wird, dass es keine Duplikate in der Eingabeliste gibt, und indem nur Unterlisten erzeugt werden, die in der gleichen Reihenfolge wie in der ursprünglichen Liste sind.

Die Längenberechnung könnte faktorisiert werden, indem l s Länge als Argument von choose übergeben wird. Das würde den Code weniger lesbar, aber effizienter machen.

Für die faule Version streuen Sie "faul" und "Lazy.force" auf den Code ...

%Vor%

BEARBEITEN:

A lazy_list_append , wie es aus den folgenden Kommentaren notwendig erscheint:

%Vor%     
Pascal Cuoq 19.10.2010, 15:21
quelle
7

Wieder einstecken mit einer Haskell-Lösung (es ist einfacher, mit faulen Listen zu arbeiten, da sie eingebaut sind):

%Vor%

Die ersten beiden Fälle ergeben sich aus den Eigenschaften der Binomialkoeffizienten und genauer gesagt: n choose 0 = 1 für alle n einschließlich n=0 (deshalb behandelt es zuerst den Fall 0 choose 0 ). Der andere ist 0 choose k = 0 . Die dritte Gleichung ist die exakte Übersetzung der rekursiven Definition von Kombinationen.

Leider, wenn Sie es auf eine unendliche Liste anwenden, gibt es eine triviale Lösung zurück:

%Vor%

BEARBEITEN: OK, also wollen wir wirklich jede Kombination in einer endlichen Anzahl von Schritten durchlaufen. Bei der obigen Version verwenden wir offensichtlich nur den Ausdruck links von ++ , der nur Kombinationen erzeugt, die mit 1 beginnen. Wir können dieses Problem umgehen, indem wir eine interessante Listen-Zipping-Funktion definieren, die eine Liste erstellt, indem wir abwechselnd den Kopf jedes einzelnen auswählen seiner Argumentlisten (es ist wichtig, im zweiten Argument nicht strikt zu sein):

%Vor%

und verwenden Sie es anstelle von ++ :

%Vor%

sieht:

%Vor%

Alle 10 choose 3 Kombinationen sind da!

    
Daniel Velkov 19.10.2010 18:01
quelle
3
___ qstnhdr ___ Lazy "n wähle k" in OCaml ___ tag123funktionale Programmierung ___ Funktionale Programmierung ist ein Programmierparadigma, das auf der Erzeugung von Abstraktionen unter Verwendung von Funktionen basiert, die Nebeneffekte und Zustandsänderungen vermeidet. Reine funktionale Programmierung ist threadsicher. ___ tag123ocaml ___ OCaml ist eine streng statisch typisierte funktionale Programmiersprache, die sich auf Expressivität, Korrektheit und Effizienz konzentriert. ___ answer3969933 ___

Hier ist eine strenge und suboptimale Version. Ich hoffe es ist klar. Sie vermeidet Duplikate, indem angenommen wird, dass es keine Duplikate in der Eingabeliste gibt, und indem nur Unterlisten erzeugt werden, die in der gleichen Reihenfolge wie in der ursprünglichen Liste sind.

Die Längenberechnung könnte faktorisiert werden, indem %code% s Länge als Argument von %code% übergeben wird. Das würde den Code weniger lesbar, aber effizienter machen.

Für die faule Version streuen Sie "faul" und "Lazy.force" auf den Code ...

%Vor%

BEARBEITEN:

A %code% , wie es aus den folgenden Kommentaren notwendig erscheint:

%Vor%     
___ answer3971240 ___

Wieder einstecken mit einer Haskell-Lösung (es ist einfacher, mit faulen Listen zu arbeiten, da sie eingebaut sind):

%Vor%

Die ersten beiden Fälle ergeben sich aus den Eigenschaften der Binomialkoeffizienten und genauer gesagt: %code% für alle %code% einschließlich %code% (deshalb behandelt es zuerst den Fall %code% ). Der andere ist %code% . Die dritte Gleichung ist die exakte Übersetzung der rekursiven Definition von Kombinationen.

Leider, wenn Sie es auf eine unendliche Liste anwenden, gibt es eine triviale Lösung zurück:

%Vor%

BEARBEITEN: OK, also wollen wir wirklich jede Kombination in einer endlichen Anzahl von Schritten durchlaufen. Bei der obigen Version verwenden wir offensichtlich nur den Ausdruck links von %code% , der nur Kombinationen erzeugt, die mit 1 beginnen. Wir können dieses Problem umgehen, indem wir eine interessante Listen-Zipping-Funktion definieren, die eine Liste erstellt, indem wir abwechselnd den Kopf jedes einzelnen auswählen seiner Argumentlisten (es ist wichtig, im zweiten Argument nicht strikt zu sein):

%Vor%

und verwenden Sie es anstelle von %code% :

%Vor%

sieht:

%Vor%

Alle %code% Kombinationen sind da!

    
___ qstntxt ___

Als Teil eines größeren Problems beim Aufzählen einer Menge muss ich eine OCaml-Funktion "choose" schreiben, die eine Liste aufnimmt und als Liste aller möglichen Sequenzen der Größe k aus Elementen dieser Liste ausgibt (ohne sich zu wiederholen) Sequenzen, die durch Permutation voneinander erhalten werden können). Die Reihenfolge in der Endliste ist nicht relevant.

Zum Beispiel

%Vor%

Irgendwelche Ideen?

Ich möchte die ganze Sache faul haben und eine faule Liste ausgeben, aber wenn Sie eine strikte Lösung haben, wird das auch sehr nützlich sein.

    
___ tag123listmanipulation ___ Die Listenmanipulation deckt alle Operationen auf einer Liste in Bezug auf ihren Inhalt ab. ___ tag123lazyevaluation ___ Lazy Evaluation bezieht sich auf eine Vielzahl von Konzepten, die eine Evaluierung vermeiden wollen eines Ausdrucks, außer wenn sein Wert benötigt wird, und um die Ergebnisse der Auswertung eines Ausdrucks unter allen Verwendungen seines Ausdrucks zu teilen, so dass kein Ausdruck benötigt wird mehr als einmal bewertet werden. ___
Surikator 19.10.2010 17:33
quelle