2015-10-23 15 views
5

Ich versuche, einen Code zu erstellen, der alle Teilmengen eines Satzes in der Reihenfolge generiert. Das heißt, sollteLänge geordnete Untergruppen?

X = []; 
X = [1]; 
X = [2]; 
X = [3]; 
X = [1,2]; 
X = [1,3]; 
X = [2,3]; 
X = [1,2,3]. 

Die innere Ordnung nicht so wichtig ist, nur erzeugen subset([1,2,3], X) Aufruf, dass die kleinsten Untergruppen aufgeführt sind erste (dh ist mir egal, wenn [2,3] vor [1 kommt , 2], nur dass 1, [2] und [3] sind vor [2,3]).

-

Ich habe bisher zwei Ansätze ausprobiert. Zuerst habe ich versucht, das Prädikat selbst zu machen ...

subset([], []). 
subset(List, []). 
subset(List, [N]) :- 
    member(N, List). 

subset(List, [N|Rest]) :- 
    !, 
    nth0(I, List, N), 
    findall(E, (nth0(J, List, E), J > I), NewList), 
    subset2(NewList, Rest). 

... aber es kommt nicht einmal annähernd so wie geplant. Zweitens habe ich versucht, das powerset (mit this subset predicate) und die Bestellung mit list_to_ord_set/2, aber ich konnte es auch nicht funktionieren.

Hilfe?

Antwort

1

ich nicht so elegante Lösung gefunden habe ... erfordert es einen Schnitt und einige builtins

subset(Xs, Ys) :- 
    length(Xs, L), 
    between(0, L, N), 
    length(Ys, N), 
    assign(Xs, Ys). 

assign(_, []) :- !. 
assign([X|Xs], [X|Ys]) :- 
    assign(Xs, Ys). 
assign([_|Xs], Ys) :- 
    assign(Xs, Ys). 

wie @Fatalize erwähnt, können wir den Schnitt vermeiden, nur die leere Liste zwingt auf erstes Argument von 1^Klausel:

assign([], []). 
assign([X|Xs], [X|Ys]) :- 
    assign(Xs, Ys). 
assign([_|Xs], Ys) :- 
    assign(Xs, Ys). 

vermieden I 2^3^Klauseln zu tauschen, so dass die 'natürliche' Ordnung noch schön

+2

Sie brauchen den Schnitt nicht, wenn Sie 'assign ([], []).' Anstelle Ihrer ersten Regel verwenden? Wenn Sie die letzte Auswertung loswerden wollen, die aus irgendeinem Grund 'false' ausgibt, können Sie einfach die Reihenfolge der zweiten und dritten' assign' Regeln ändern. Es ändert die Reihenfolge, ist aber immer noch gültig, je nachdem was OP wünscht. – Fatalize

+0

@Fatalize: der Schnitt ist erforderlich, um doppelte Lösungen zu vermeiden, und die Anon var Unterlisten von Xs akzeptieren – CapelliC

+1

Ich verstehe es nicht. Mit diesen Änderungen erhalte ich genau die gleichen Ergebnisse. Möchten Sie ein Beispiel angeben, das den cut und die anonyme Variable erfordert? – Fatalize

3

immer auch mit DCG notation betrachten erhalten wHE n Listen beschreiben.

Zum Beispiel:

list_sublist(Ls0, Ls) :- 
     same_length(Ls0, Ls1), 
     append(Ls, _, Ls1), 
     phrase(sublist(Ls0), Ls). 

sublist([])  --> []. 
sublist([L|Ls]) --> ([] ; [L]), sublist(Ls). 

Beispielabfrage:

?- list_sublist([a,b,c], Ls). 
Ls = [] ; 
Ls = [c] ; 
Ls = [b] ; 
Ls = [a] ; 
Ls = [b, c] ; 
Ls = [a, c] ; 
Ls = [a, b] ; 
Ls = [a, b, c] ; 
false. 

Ein weiteres Beispiel:

?- list_sublist(Ls, [b,c]). 
Ls = [b, c] ; 
Ls = [_G511, b, c] ; 
Ls = [b, _G514, c] ; 
Ls = [b, c, _G517] ; 
etc. 

allgemeinsten Fall:

?- list_sublist(Xs, Ys). 
Xs = Ys, Ys = [] ; 
Xs = [_G513], 
Ys = [] ; 
Xs = Ys, Ys = [_G513] 
Xs = [_G513, _G516], 
Ys = [] ; 
etc. 
+2

s (X): Ich grabe wirklich 'Unterliste // 1'. Wie wäre es mit dem Schreiben von '([] | [L])' anstelle von '([]; [L])'? – repeat

+1

Ich bin generell * sehr dafür *, '' 'in DCGs zu verwenden, +1! Wahrscheinlich ist es jedoch lesbarer, wenn die Variable nicht genau "L" heißt, oder? Vergleichen Sie '[] | [L] 'oder das sogar etwas weniger lesbare' [] | [L] 'mit' []; [L] 'oder' []; [L] '.Da ich in diesem Fall wirklich 'L' verwenden möchte, finde ich' '' 'in diesem konkreten Fall etwas besser lesbar. Ich würde auf jeden Fall '|' in Fällen wie '[] | verwenden [_] '. – mat

+1

Haben Sie irgendwelche Daten über die visuelle Ähnlichkeit von ASCII-Zeichen unter schwierigen Lesebedingungen? Sie mögen die Jargon-Datei "große Runen", aber nicht für Groß- und Kleinbuchstaben, sondern Groß- und Großbuchstaben. Ich denke, "L" ist schlecht, wenn "[| I_17" in der Nähe vorhanden ist (plus ein paar mehr, wenn wir * kursiv * zur Hervorhebung von etw in Betracht ziehen) ... – repeat