我是prolog的新手,作为一项学校作业,我需要在Prolog中写一个DCG然后写一个perdicate来确定一些东西。输入是一个String,如下所示:
Date,Exchange,Tape A,Tape A %,Tape B,Tape B %,Tape C,Tape C %,Total,Total %,Tape A Moving,Tape A % Moving,Tape B Moving,Tape B % Moving,Tape C Moving,Tape C % Moving,Total Moving, Total % Moving
02/18/2014,NASDAQ,473515614,13.80%,119199766,11.40%,520888794,27.50%,1113604174,17.50%,511929756,14.30%,145320601,12.30%,532617511,26.30%,1189867868,17.50%
02/18/2014,NYSE,721710805,21.10%,0,0.00%,0,0.00%,721710805,11.40%,707472219,19.70%,0,0.00%,0,0.00%,707472219,10.40%
第一行是标题。
我写了DCG解析器:
row([[Date,Stock,A,PerA,B,PerB,C,PerC,Total,PerTotal,A2,A3,B2,B3,C2,C3,T2,T3,'\n']|Rows]) -->
date(Date), separe,stock(Stock),
integer(A),separe,number(PerA),"%",separe,
integer(B),separe,number(PerB),"%",separe,
integer(C),separe,number(PerC),"%",separe,
integer(Total),separe,number(PerTotal),"%",separe,
integer(A2),separe,number(A3),"%",separe,
integer(B2),separe,number(B3),"%",separe,
integer(C2),separe,number(C3),"%",separe,
integer(T2),separe,number(T3),"%",separe,
row(Rows).
row(Rows) -->
string(_),"\n" ,
row(Rows).
row([]) --> [].
date(D/M/Y) -->
integer(D), "/", integer(M), "/", integer(Y).
stock([F|Ks]) -->
[F], {F \= 0' }, string(Ks).
separe --> white, whites.
它工作正常但是在解析输入后我需要找到具有最大总数的元素。 我做了类似的事情:
findMaxTotal([],X,Ret).
findMaxTotal([R1|Rest],X,Ret):-
nth1(9,R1,X),
findMaxTotal(Rest,Y,max(Ret,X)).
但它不起作用,我无法在SWI prolog中调试它以理解原因。
有没有人有关于如何在列表列表中找到最大值的任何提示?
谢谢!
答案 0 :(得分:1)
我认为您可以使用findall/3
和max_list/2
来完成此操作。见下面的例子。 Row
包含第二个元素是数字的列表列表。使用findall/3
将数字提取到单独的列表中,然后使用max_list/2
找到最大数字。
?- Row = [['a', 5, test(a)], ['b', 10, test(b)], ['c', -1, test(c)]],
findall(Value, (member(SubList, Row), nth1(2, SubList, Value)), ListValues),
max_list(ListValues, Max).
Row = [[a, 5, test(a)], [b, 10, test(b)], [c, -1, test(c)]],
ListValues = [5, 10, -1],
Max = 10.
这里我将它括在一个很好的谓词中:
findMaxInSubList(Data, ElemIndex, Max) :-
findall(Value, (member(SubList, Data), nth1(ElemIndex, SubList, Value)), ListValues),
max_list(ListValues, Max).
示例输入和输出:
?- sample_data(Row), findMaxInSubList(Row, 2, Max).
Row = [[a, 5, test(a)], [b, 10, test(b)], [c, -1, test(c)]],
Max = 10.
答案 1 :(得分:1)
原始尝试中的一个问题是此查询:
findMaxTotal(Rest,Y,max(Ret,X)).
Prolog在处理查询参数时不评估算术表达式。 max/2
必须出现在is/2
的第二个参数或要评估的算术比较器中。
原始代码的修复,这是一个经典的Prolog列表处理示例,将是:
findMaxTotal([R|Rest], Ret) :-
findMaxTotal(T, R, Ret).
findMaxTotal([], X, X).
findMaxTotal([R|Rest], X, Ret):-
nth1(9, R, X1),
Y is max(X, X1),
findMaxTotal(Rest, Y, Ret).
这实际上也可以按如下方式编写:
findMaxTotal([R|Rest], Ret) :-
findMaxTotal(T, R, Ret).
findMaxTotal([], X, Ret) :-
Ret is X. % Evaluate X
findMaxTotal([R|Rest], X, Ret):-
nth1(9, R, X1),
findMaxTotal(Rest, max(X, X1), Ret).
此处,在基本案例findMaxTotal([], X, Ret)
的正文中,Ret
最终会根据X
来评估max(max(max(max(3, 5), 2), 7), 6)
,max
。 (原始列表的每个元素都会有maplist
。)
这样的列表处理模式非常适合max_list/2
谓词和谓词find_max_total(Data, ElemIndex, Max) :-
maplist(nth1(ElemIndex), Data, Values),
max_list(Values, Max).
的使用,这两种谓词都可以在SWI和GNU Prolog(以及其他人)中使用:
find_max_total(Data, 9, Max).
并且,在您的情况下,使用查询:
find_max_record([Datum|Data], ElemIndex, MaxDatum) :-
nth1(ElemIndex, Datum, Value),
find_max_record(Data, Datum, Value, ElemIndex, MaxDatum).
find_max_record([], MaxDatum, _, _, MaxDatum).
find_max_record([Datum|Data], MaxDatumSoFar, MaxValueSoFar, ElemIndex, MaxDatum) :-
nth1(ElemIndex, Datum, Value),
( Value > MaxValueSoFar
-> NewMaxDatum = Datum,
NewMaxValue = Value
; NewMaxDatum = MaxDatumSoFar,
NewMaxValue = MaxValueSoFar
),
find_max_record(Data, NewMaxDatum, NewMaxValue, ElemIndex, MaxDatum).
<强>附录强>
如果您需要获取在给定列中具有最大值的整个记录,则第一个递归方法可能是最直接的方法。但是,我们不仅仅是携带价值,而且还带有整个记录。此外,我们需要一个明确的最大检查,以便我们知道最大值来自哪条记录:
maplist
作为上述['a', 5, test(a)]
方法的类比,但效率不高,将使用我们想要比较的元素“索引”数据数据的每一行。诸如5-['a', 5, test(a)]
之类的行变为maplist/3
,然后我们使用max_list_ex/2
来转换整个数据列表。然后我们可以将更通用的max_list/2 we can write using the more general
(一个% Extended max_list/2 which does general term comparison
max_list_ex([H|T], M) :-
max_list_ex(T, H, M).
max_list_ex([H|T], A, M) :-
H @> A,
max_list_ex(T, H, M).
max_list_ex([H|T], A, M) :-
H @=< A,
max_list_ex(T, A, M).
max_list_ex([], M, M).
% Maps an index and a Datum (a list) to Elem-Datum
index_elem(ElemIndex, Datum, Elem-Datum) :-
nth1(ElemIndex, Datum, Elem).
find_max_record(Data, ElemIndex, MaxRec) :-
maplist(index_elem(ElemIndex), Data, IndexedData),
max_list_ex(IndexedData, _-MaxRec).
@`术语比较器)应用于该索引的数据列表并获得结果。:
{{1}}