2016-05-03 5 views
2

Ich möchte die Anzahl der Elemente in einer Liste zählen, die eine Beziehung mit dem folgenden Element haben. Das Prädikat I funktioniert, indem es eine Akkumulatorvariable verwendet, die es erhöht, wenn das Prädikat related true zurückgibt. Der folgende Beispielcode überprüft, wie oft ein Element größer als sein vorheriges Element ist.Liste - Atome zählen, die zu ihrem vorherigen Ausdruck gehören

So zum Beispiel

count_list([1,2,3,2,1,3,2],Count). 

sollte zurückkehren 3.

Der Code fast funktioniert. Es erhöht die Akkumulatorvariable korrekt. Die Funktion gibt jedoch false zurück, wenn sie versucht, die letzte 2 am Ende mit der nicht vorhandenen nächsten zu vergleichen.

listofitems([],N,N). 
%count number of items which are related to the previous 
listofitems([A,B|T],Acc,N) :- 
    write(A),write(' '), write(B), 
    (related(A,B) -> Acc1 is Acc+1 ; Acc1 = Acc), 
    write(Acc1),write('\n'), 
    listofitems([B|T],Acc1,N). 

count_list(L,N):- 
    listofitems(L,0,N). 

%define the relationship to be counted 
related(A,B):- 
    B>A. 

Hat jemand irgendwelche Vorschläge, wie man eine elegante Beendigungsbedingung erstellt, damit ich den akkumulierten Wert zurückgeben kann?

Antwort

1

nicht sicher

ein elegantes Endbedingung

meine ganze Code würde

?- Vs=[1,2,3,2,1,3,2], aggregate_all(count, (append(_,[X,Y|_], Vs), X<Y), Count). 

sein Das ist alles ...

Wenn Sie etwas komplexer brauchen Denken Sie daran, dass die Bibliothek (clpfd) mehr zu bieten hat.

4

Hat jemand irgendwelche Vorschläge, wie man eine elegante Beendigungsbedingung erstellt, damit ich den akkumulierten Wert zurückgeben kann?

Das Problem, das Sie haben, ist, dass Ihre Abfrage fehlschlägt. Versuchen Sie zunächst, die Abfrage so weit wie möglich zu minimieren. Sicherlich erwarten Sie es für die Arbeit:

?- listofitems([], Count). 
    Count = 0. 

Doch es scheitert bereits für:

?- listofitems([1], Count). 
    false. 

So wollen wir versuchen, in den Grund dafür zu graben. Und da Ihr Programm ist rein (abgesehen von diesen write s), ist es möglich, dies ein wenig besser zu diagnostizieren, indem Sie eine Generalisierung Ihres Programms. Ich ziehe es bei solchen Verallgemeinerungen aussehen, wie ich will nicht zu viel (Überanstrengung der Augen und so weiter) lesen:

 
:- op(950, fy, *). 
*_. 

listofitems([], N,N). 
listofitems([A,B|T], Acc,N) :- 
    *(related(A,B) -> Acc1 is Acc+1 ; Acc1 = Acc), 
    *listofitems([B|T], Acc1,N). 

count_list(L,N):- 
    listofitems(L,0,N). 


?- count_list([1], Count). 
    false. 

Auch diese Verallgemeinerung nicht! So verzweifelt versuche ich jetzt die allgemeinste Abfrage zu fragen. Es ist wie wenn ich frage one thing after the other und bekomme ein Noe nach einem Nein. Gut, das ist Prolog, denn wir können fragen: "Sag mir einfach alles, was du weißt".

?- count_list(Es,Count). 
    Es = [], Count = 0 
; Es = [_,_|_]. 

So ist es nur der Fall für die leere Liste und Listen mit mindestens zwei Elementen. Aber es gibt keine Antwort für One-elementierte Listen!Sie müssen also das Programm irgendwie verallgemeinern.

Eine natürliche Art und Weise eine Tatsache

listofitems([_], N, N). 

Als kleinere Bemerkung hinzuzufügen wäre, dies ist kein „Endbedingung“, sondern ein „Basisfall“ bezeichnet.


Und wenn Sie wirklich Ihren Code ausfindig machen wollen, empfehle ich these techniques statt writes manuell hinzufügen. Sie sind viel zu fehleranfällig.

4

Wenn die alle Listenelemente ganze Zahlen sind und Ihr Prolog-System unterstützt , können Sie wie folgt vorgehen:

 
:- use_module (library (clpfd)). 
:- use_module(library(lists), [last/3]). 
:- use_module(library(maplist) , [maplist/4]). 

benachbarte Elemente beziehen, Blick auf zwei Teil-Listen von [E|Es], Es und Fs. Wenn, sagen wir, [E|Es] = [1,2,3,2,1,3,2] hält ...

  • ... dann Fs fehlt die letzte Artikel (Fs = [1,2,3,2,1,3,2]) ...
  • ... und Es fehlt die ersten Artikel (Es = [1,2,3,2,1,3,2]) .

maplist/4 und i0_i1_gt01/3 Karte Listenelemente in Fs und Es-0/1 entsprechen:

 
i_j_gt01(I, J, B) :-     % if I #< J then B #= 1 
    I #< J  #<=> B.      % if I #>= J then B #= 0 

?- maplist(i_j_gt01, [1,2,3,2,1,3], [2,3,2,1,3,2], Bs). 
Bs = [1,1,0,0,1,0]. 

Last, resümieren [1,1,0,0,1,0] mit sum/3:

?- sum([1,1,0,0,1,0], #=, N). 
N = 3. 

Sagen wir es alle zusammen!

 
count_adj_gt([E|Es], N) :- 
    last (Fs, _, [E|Es]),    % or: ` append (Fs, [_], [E|Es])` 
             % or: ` list_butlast ([E|Es], Fs)` 
    maplist (i_j_gt01, Es, Fs, Bs), 
    sum (Bs, #= , N). 

Beispielabfrage mit SICStus Prolog 4.3.2:

?- count_adj_gt([1,2,3,2,1,3,2], N). 
N = 3.        % succeeds deterministically 
+1

Warnung: maplist/4 in der aktuellen SICStus nicht monoton ist! – false

Verwandte Themen