列表处理计算,在Prolog中找到朋友要访问的目的地

列表处理计算,在Prolog中找到朋友要访问的目的地,prolog,Prolog,我正试图编写一个谓词来计算一组朋友将访问哪个目的地。 朋友们会像这样列出他们喜欢的国家 choice(marie, [peru,greece,vietnam]). choice(jean, [greece,peru,vietnam]). choice(sasha, [vietnam,peru,greece]). choice(helena,[peru,vietnam,greece]). choice(emma, [greece,peru,vietnam]). 我想写一个名为where

我正试图编写一个谓词来计算一组朋友将访问哪个目的地。 朋友们会像这样列出他们喜欢的国家

choice(marie, [peru,greece,vietnam]). 
choice(jean, [greece,peru,vietnam]). 
choice(sasha, [vietnam,peru,greece]). 
choice(helena,[peru,vietnam,greece]). 
choice(emma, [greece,peru,vietnam]).

我想写一个名为where的谓词,它需要两个参数来执行计算。 我想到的公式是,第一个国家值3分,第二个国家值2分,最后一个国家值1分

这是一个我正在努力实现的例子

?- where([marie,jean,sasha,helena,emma],Country). 
peru .
到目前为止,我有这个

where([], X).
where([H|T], N) :- choice(H, [A|B]), where(T,N).
它允许我遍历所有不同的朋友并显示他们的选择,但我无法遍历选择列表并为目的地分配点数


我应该如何遍历每个朋友的选择列表并分配点来计算最佳目的地?

虽然这可以解决您的问题,但我知道它使用了许多您没有看到的谓词。所以,把这看作是一个超越自我、学到很多东西的机会

即使您不完全理解,测试中也有足够的细节和中间结果,您应该能够找到您创建的适当解决方案

而且,这绝对不是有效的,这只是一个概念的快速证明,我做了,看看如何可以做到这一点

choice(marie, [peru,greece,vietnam]).
choice(jean, [greece,peru,vietnam]).
choice(sasha, [vietnam,peru,greece]).
choice(helena,[peru,vietnam,greece]).
choice(emma, [greece,peru,vietnam]).

destinations(Destinations) :-
    findall(D1,choice(_,D1),D2),
    flatten(D2,D3),
    list_to_set(D3,Destinations).

init_weights(Destinations,Weights) :-
    empty_assoc(Assoc),
    init_weights(Destinations,Assoc,Weights).

init_weights([],Weights,Weights).
init_weights([H|T],Assoc0,Weights) :-
    put_assoc(H,Assoc0,0,Assoc1),
    init_weights(T,Assoc1,Weights).

update_weights([C1,C2,C3],Weights0,Weights) :-
    del_assoc(C1,Weights0,Value0,Weights1),
    Value1 is Value0 + 3,
    put_assoc(C1,Weights1,Value1,Weights2),
    del_assoc(C2,Weights2,Value2,Weights3),
    Value3 is Value2 + 2,
    put_assoc(C2,Weights3,Value3,Weights4),
    del_assoc(C3,Weights4,Value4,Weights5),
    Value5 is Value4 + 1,
    put_assoc(C3,Weights5,Value5,Weights).

person_weight(Person,Weights0,Weights) :-
    choice(Person,[C1,C2,C3]),
    update_weights([C1,C2,C3],Weights0,Weights).

people(People) :-
    findall(Person,choice(Person,_),People).

choice(Destination) :-
    destinations(Destinations),
    init_weights(Destinations,Weights0),
    people(People),
    update_choices(People,Weights0,Weights1),
    cross_ref_assoc(Weights1,Weights),
    max_assoc(Weights, _, Destination),
    true.

cross_ref_assoc(Assoc0,Assoc) :-
    assoc_to_list(Assoc0,List0),
    maplist(key_reverse,List0,List),
    list_to_assoc(List,Assoc).

key_reverse(Key-Value,Value-Key).

update_choices([],Weights,Weights).
update_choices([Person|People],Weights0,Weights) :-
    person_weight(Person,Weights0,Weights1),
    update_choices(People,Weights1,Weights).
测验


正如GuyCoder所建议的,您需要一个累加器来对每个人的偏好进行累加,并且/N允许这样做

choice(玛丽、[秘鲁、希腊、越南])。
选择(吉恩,[希腊、秘鲁、越南])。
选择(萨沙[越南、秘鲁、希腊])。
选择(赫勒拿,[秘鲁、越南、希腊])。
选择(艾玛,[希腊、秘鲁、越南])。
where(人,where):-
foldl([Person,State,Updated]>>(选项(Person,C),update(State,C,Updated)),
人,
[0=希腊,0=秘鲁,0=越南],
Pref),
聚合(最大值(S,S=W)、成员(S=W,Pref)、最大值(其中)。
%排序(Pref,Sorted),
%最后一个(已排序,=其中)。
更新(S0[A,B,C],S3):-
更新(S0,3,A,S1),
更新(S1、2、B、S2),
更新(S2,1,C,S3)。
更新(L、V、C、U):-
附加(X[Y=C | Z],L),
P是Y+V,
附加(X[P=C | Z],U)。

我留下了用单目标聚合/3替换的最后两个目标的注释,因此您可以尝试理解语法…

您需要一个
累加器。
只需谷歌搜索
Prolog累加器
,您会发现许多示例。
:- begin_tests(destination).

test(destinations) :-
    destinations([peru, greece, vietnam]).

test(init_weights) :-
    destinations(Destinations),
    init_weights(Destinations,Weights),
    assoc_to_list(Weights,[greece-0, peru-0, vietnam-0]).

test(update_weights) :-
    destinations(Destinations),
    init_weights(Destinations,Weights0),
    update_weights([peru,greece,vietnam],Weights0,Weights),
    assoc_to_list(Weights,[greece-2,peru-3,vietnam-1]).

test(person_weight) :-
    destinations(Destinations),
    init_weights(Destinations,Weights0),
    person_weight(jean,Weights0,Weights),
    assoc_to_list(Weights,[greece-3,peru-2,vietnam-1]).

test(people) :-
    people([marie,jean,sasha,helena,emma]).

test(update_choices) :-
    destinations(Destinations),
    init_weights(Destinations,Weights0),
    people(People),
    update_choices(People,Weights0,Weights),
    assoc_to_list(Weights,[greece-10,peru-12,vietnam-8]).

test(cross_ref_assoc) :-
    List0 = [1-a,2-b,3-c],
    list_to_assoc(List0,Assoc0),
    cross_ref_assoc(Assoc0,Assoc),
    assoc_to_list(Assoc,[a-1,b-2,c-3]).

test(choice) :-
    choice(peru).

:- end_tests(destination).