【问题标题】:It is possible to manipulate a list generated with findall?可以操作使用 findall 生成的列表吗?
【发布时间】:2013-07-09 21:09:26
【问题描述】:

我的程序中的上下文如下:我有一些students,一些country和一些years的学习,如下这个prolog代码:

student('Steve Morris').
student('Joe Jez').
student('Carlos Sethi').
student('Natasha Carter').

country('Steve Morris', usa).
country('Joe Jez', usa).
country('Carlos Sethi', usa).
country('Natasha Carter', france).

years('Steve Morris', 3).
years('Joe Jez', 1). 
years('Carlos Sethi', 4).
years('Natasha Carter', 4). 

scholarship(A) :- country(A,B), B = france.
scholarship(A) :- years(A,C), C > 2.

我想给我的一名学生提供一份奖学金。为此,我将使用一些提高“奖学金系数”的规则获得更大奖学金系数的学生将获得奖学金

第一条规定学生必须来自法国,第二条规定学生必须有两年以上的学习。

所以,当我执行scholarship(X) 时,我得到的是:

?- scholarship(X).
X = 'Natasha Carter' ;    % Only student who matches the first rule
X = 'Steve Morris' ;      % All students from now on, match the second rule
X = 'Carlos Sethi' ;
X = 'Natasha Carter'.

话虽如此,我正在尝试做一个程序,试图获取最终获得奖学金的学生的姓名。首先,我尝试先执行一个谓词findall 来逐一过滤所有符合这些规则的学生,并将其放在一个列表中:

?- findall(X, scholarship(X), L).
L = ['Natasha Carter', 'Steve Morris', 'Carlos Sethi', 'Natasha Carter'].

这是预期结果,因为使用了scholarship(X)

现在,看来我需要生成的列表来过滤结果并满足我的要求。请记住,在上面的示例中,我期望达到的结果至少是一个表明学生及其奖学金因素的列表,如下所示(不一定准确):

[['Natasha Carter', 2], ['Steve Morris', 1], ['Carlos Sethi', 1]].

这是一种操作findall生成的列表的方法吗?或者我当然需要另一种方法来解决这个问题?

编辑:问题建模有一点很重要:所有规则都有相同的奖学金因子值,所以当一个学生满足一个规则时,无论是哪一个,奖学金系数应升至 1。

问题更新:感谢 Mog,我有一个解决问题的方法,使用辅助列表应用 msort/2,这就是我所得到的:

?- findall(X, scholarship(X), L), msort(L, L1).
L = ['Natasha Carter', 'Steve Morris', 'Carlos Sethi', 'Natasha Carter'],
L1 = ['Carlos Sethi', 'Natasha Carter', 'Natasha Carter', 'Steve Morris'].

【问题讨论】:

  • 感谢msort/2,您可以从排序列表开始。完成后,可以编写一个简单的谓词,在每个连续的相似元素之后增加一个计数器并返回所需的结果。
  • 次要:替换country(A,B), B = france. par country(A, france).
  • 解决问题的一种方法,我执行了以下命令?- findall(X, scholarship(X), L), msort(L, L1).,这是输出:L = ['Natasha Carter', 'Steve Morris', 'Carlos Sethi', 'Natasha Carter'], L1 = ['Carlos Sethi', 'Natasha Carter', 'Natasha Carter', 'Steve Morris'].

标签: list prolog


【解决方案1】:

更简单的方法应该是给scholarship(X) 增加一个排名(我已经添加了规则'index'),然后使用 setof 得到一个排序列表,从低到高:

scholarship(1,A) :- country(A,B), B = france.
scholarship(2,A) :- years(A,C), C > 2.

?- setof(R-X, scholarship(R,X), L).

请注意,我利用 setof 执行的排序将列表元素更改为更有用的格式。

edit:对不起,我提出了一个无用的修改。一个更合适的答案会建议

?- findall(N-X, (bagof(_, scholarship(X), T), length(T, N)), L).
L = [1-'Carlos Sethi', 2-'Natasha Carter', 1-'Steve Morris'].

【讨论】:

  • 你的代码是可以的,但是我想根据规则评估得到的奖学金因素来排序学生时,会出现学生按照规则数量排名的问题。
  • @CristianC 通常(这适用于所有编程,而不仅仅是 Prolog)通过明确其余要求,您将使系统的其余部分能够做出决策。 CapelliC 可能没有正确地读懂您的想法,但该技术将推广到您的实际问题,并且以比试图操纵 Prolog 内置函数的内部工作更简单的方式。
  • 谢谢丹尼尔。今晚我实际上有点累了,没听懂这个问题。
【解决方案2】:

我通过使用名为的注册表结构为自己找到了一个替代解决方案:

reg(C, N)

其中C是人名,N是人名出现在findall生成的列表中的次数(使用msort/2,本方案效果,仅用于订购目的)。

listsort(L1) :- findall(X, scholarship(X), L), msort(L, L1).

compress([],[]).
compress([X|Xs],Ys):-comp(Xs,X,1,Ys).

comp([],C,N,[reg(C,N)]).
comp([X|Xs],X,N,Ys):-N1 is N+1, comp(Xs,X,N1,Ys).
comp([X|Xs],Y,N,[reg(Y,N)|Ys]):-  X\=Y, comp(Xs,X,1,Ys).

predic(S2) :- listsort(S1), compress(S1, S2).

所以原始问题的输出看起来与提议的问题相似(唯一的区别是在原始问题中,注册表按N 排序:

?- predic(K).
K = [reg('Carlos Sethi', 1), reg('Natasha Carter', 2), reg('Steve Morris', 1)] 

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2022-01-23
    • 2017-02-05
    • 1970-01-01
    • 2020-04-26
    • 2021-03-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多