2014-11-21 9 views
5

Ich versuche, eine Funktion zu machen, die eine Liste variabler Länge in drei Listen gleicher Länge in der Reihenfolge aufteilt. Das Folgende teilt es in drei auf, aber Prozesse fügen sie einzeln in jede Liste ein.Teilen einer einzelnen Liste in drei in der Reihenfolge mit Prolog

Ein Beispiel dafür, was ich will, ist:

[1, 2, 3, 4, 5] -> [1, 2], [3, 4], [5] 

Ein weiteres Beispiel wäre:

[8, 7, 6, 5, 4, 3, 2, 1] -> [8, 7, 6], [5, 4, 3], [2, 1]. 

Der folgende Code teilt sie durch zu einer Zeit, in jeder Liste ein Einfügen:

div([], [], [], []). 
div([X], [X], [], []). 
div([X,Y], [X], [Y], []). 
div([X,Y,Z|End], [X|XEnd], [Y|YEnd], [Z|ZEnd]):- 
    div(End, XEnd, YEnd, ZEnd). 

Dieser Code wird ausgegeben:

[1, 2, 3, 4, 5] -> [1, 4], [2, 5], [3] 

Wie kann ich dieses Problem beheben?

Antwort

5

Die Antwort von @Boris endet nicht, wenn die Länge der Liste des ersten Arguments nicht bekannt ist. Um dies zu sehen, besteht keine Notwendigkeit, weiter als das erste Ziel suchen mit einem :

 
div(L, L1, L2, L3) :- 
    length(L, Len), false, 
    % here you compute for example Len1 and Len2 
    length(L1, Len1), 
    length(L2, Len2), 
    append(L1, L1_suffix, L), 
    append(L2, L3, L1_suffix). 

Auf der anderen Seite, Ihr ursprüngliches Programm hatte quite nice termination properties. KTI ergab folgende optimale Beendigung Eigenschaft:

div(A,B,C,D) terminates_if b(A);b(B);b(C);b(D). 

Mit anderen Worten, die Kündigung zu gewährleisten, müssen Sie nur ein einziges Argument (entweder A oder B oder C oder D) eine konkrete Liste sein, die endlich und Boden (das ist was b(..) bedeutet). Das ist eine sehr starke Abbruchbedingung. Es ist wirklich schade, dass die Argumente nicht passen! Warum verallgemeinern Sie Ihr Programm nicht? Das einzige Problem ist, dass es die Listenelemente einschränkt. Also werde ich alle Variablennamen der Listenelemente durch _ s ersetzen:

gdiv([], [], [], []). 
gdiv([_], [_], [], []). 
gdiv([_,_], [_], [_], []). 
gdiv([_,_,_|End], [_|XEnd], [_|YEnd], [_|ZEnd]):- 
    gdiv(End, XEnd, YEnd, ZEnd). 

Die very same Abschlusseigenschaften halten für dieses Programm.

Leider ist es jetzt ein bisschen zu allgemein.Boris-Lösung kann nun umgewidmet werden:

divnew(Zs, As, Bs, Cs) :- 
    gdiv(Zs, As, Bs, Cs), 
    append(As, BsCs, Zs), 
    append(Bs, Cs, BsCs). 

Mein bevorzugter Weg, um das gleiche auszudrücken würde eher sein:

divnew(Zs, As, Bs, Cs) :- 
    gdiv(Zs, As, Bs, Cs), 
    phrase((seq(As), seq(Bs), seq(Cs)), Zs). 

Siehe other answers für eine Definition von seq//1.

+0

Danke @false. Ich verstehe auch, was Sie mir außerhalb dieser Frage zeigen wollten. – Mocking

2
div(L, L1, L2, L3) :- 
    append(L1, L1_suffix, L), 
    append(L2, L3, L1_suffix). 

Sehen Sie, wie dies die drei Listen aufteilt? Jetzt sagen Sie nicht, wie lange Sie die Listen L1, L2 und L3 erwarten. Sie können length/2 verwenden, um die Länge L zu erhalten, und die Länge der drei Ergebnisse festlegen, wenn das Prädikat nicht so allgemein sein soll, wie es momentan ist.

Da Sie "relativ gleichmäßige Länge" sagen, was relativ ist und ich es irgendwie interpretieren muss, nehmen wir an, Sie meinen, dass für eine positive Ganzzahl len und n, len = 3n, len1 = len2 = len3 = n, für k = 3n + 1 erhalten Sie len1 = n + 1, len2 = len3 = n, und für k = 3n + 2 erhalten Sie len1 = len2 = n + 1, len3 = n. Ich lasse dich herausfinden, wie man die Längen berechnet.

div(L, L1, L2, L3) :- 
    length(L, Len), 
    % here you compute for example Len1 and Len2 
    length(L1, Len1), 
    length(L2, Len2), 
    append(L1, L1_suffix, L), 
    append(L2, L3, L1_suffix). 
+0

Ich bin nicht 100% sicher, aber ich denke, Sie haben mein Problem falsch verstanden. Ich versuche die erste Liste in 3 Listen aufzuteilen. – Mocking

+0

@Mocking Haben Sie tatsächlich versucht, was dieses Prädikat tut? Auch ist noch unklar, ob es Einschränkungen bei den Längen der resultierenden Listen gibt. –

+0

Sorry, ich habe versucht, mein Problem klarer zu machen. Ich versuche, eine Liste variabler Länge in 3 gerade (oder relativ gleichmäßige) Listen aufzuteilen. Würde das tatsächlich für diesen Fall helfen? – Mocking