处理Prolog中的列表列表

时间:2019-01-24 00:45:03

标签: prolog

我是Prolog的新手,总体来说是逻辑编程。我正在尝试从已有的教科书中进行练习,并且存在以下问题:考虑一个列表列表,例如:

[[spanish, white], [italian, white], [italian, red], [canadian, blue]]

我们将“和谐”定义为一组唯一的元素,这些元素仅位于一个子列表中。内部列表的每个索引都表示类似的东西:国籍或肤色。在上面的示例中,[canadian, blue]是“和谐”,但是[italian, white]并不是因为italian中也有[italian, red]

我正在尝试创建一个遍历子列表的关系,并尝试创建最佳的“和谐”。对于上面的示例,我们应该检查第一个子列表; [spanish, white],对于每个元素,检查是否存在另一个包含该元素的子列表。如果它们是唯一的,那就是“和谐”,否则我们应该检查是否可以某种方式减少那些列表之一。输出应为:

[[spanish, white], [italian, red], [canadian, blue]]

说明:spanish已连接到white,所以我们不应该碰它,但是italian包含在whitered中。然后我们可以理解,italian必须连接到red,因为white is with是西班牙语。

最终目标是拥有唯一子列表的列表。您可以将其视为方程式系统,我们希望对其进行求解。

另一个例子:

[[spanish, white, 5], [italian, red,4], [canadian, blue,2],[canadian,red,2],[spanish, blue,4]]

输出:

 [[spanish, white, 5], [italian, red,4], [canadian, blue,2]]

说明:让我们看一下[spanish, white, 5]。我们知道spanish也位于[spanish, blue,4]中,但是blue也位于[canadian, blue,2]中。 canadian不在其他任何地方,因此blue属于canadian。这意味着spanish得到white(然后还有5)。 canadian得到2,这意味着italian得到4blue

我试图使用findall,但没有成功。我觉得这里有很多信息,这让我感到困惑。

如何从教科书中解决这个问题?

编辑

总是只有一种可能的解决方案。如果您收到类似[[spanish, white], [italian, white]]之类的信息,那么您就没有任何其他信息,应该将其保持不变。

我试图再次解决它,但没有成功。我试图以某种方式创建一个包含所有信息的哈希图,但对我来说,它不是Prolog解决方案。我认为findall可以解决此问题,但我似乎不知道如何解决。

2 个答案:

答案 0 :(得分:2)

由于值在子列表中的位置是固定的,并且所有子列表都是完整的:

harmony(As,Bs) :- maplist(dif,As,Bs).

harmonies(L,R) :-
    forall((select(A,L,S),member(B,S)), harmony(A,B))
    ->  R=L
    ;   select(_,L,T), harmonies(T,R)
    .

creasing_harmonies(L,R) :-
    setof(D-T,(harmonies(L,T),length(T,D)),R).

不确定什么是“最佳和谐”。假设是更长的时间:

?- creasing_harmonies([[spanish, white, 5], [italian, red,4], [canadian, blue,2],[canadian,red,2],[spanish, blue,4]],L),last(L,B).
L = [1-[[canadian, blue, 2]], 1-[[canadian, red, 2]], 1-[[italian, red, 4]], 1-[[spanish, blue, 4]], 1-[[spanish, white|...]], 2-[[canadian|...], [...|...]], 2-[[...|...]|...], 2-[...|...], ... - ...|...],
B = 3-[[spanish, white, 5], [italian, red, 4], [canadian, blue, 2]].

如果您的Prolog中没有dif / 2或maplist / 3,则近似值为

harmony([],[]).
harmony([E|As],[E|Bs]) :- !, fail.
harmony([_|As],[_|Bs]) :- harmony(As,Bs).

编辑

到目前为止,它的效率非常低。要获得解决方案,必须减少搜索空间:

harmonies(L,R) :-
    length(L,N),N>4,
    (   forall((select(A,L,S),member(B,S)), harmony(A,B))
    ->  R=L
    ;   select(_,L,T), harmonies(T,R)
    ).

但是让我们看看我们现在有多少个“解决方案”

?- test_data(L),aggregate(count,harmonies(L,R),C).
L = [[table, green, alex, coffee, prince], [keyboard, green, alex, coffee, bookA], [keyboard, yellow, alex, water, bookA], [cup, red, alex, water, bookB], [computer, white, john, beer|...], [cup, red, birds|...], [keyboard, green|...], [keyboard|...], [...|...]|...],
R = [[table, green, alex, coffee, prince], [computer, white, john, beer, bookD], [cup, red, birds, milk, bookC], [keyboard, yellow, sabrina, water, bookA], [dane, blue, sasha, tea|...]],
C = 5040.

5040个重复!最好在固定长度上停在第一个解决方案上。

harmonies(L,N,R) :-
    length(L,M),M>=N,
    (   forall((select(A,L,S),member(B,S)), harmony(A,B))
    ->  R=L
    ;   select(_,L,T), harmonies(T,R)
    ).

?- test_data(L),harmonies(L,5,R).
L = [[table, green, alex, coffee, prince], [keyboard, green, alex, coffee, bookA], [keyboard, yellow, alex, water, bookA], [cup, red, alex, water, bookB], [computer, white, john, beer|...], [cup, red, birds|...], [keyboard, green|...], [keyboard|...], [...|...]|...],
R = [[table, green, alex, coffee, prince], [computer, white, john, beer, bookD], [cup, red, birds, milk, bookC], [keyboard, yellow, sabrina, water, bookA], [dane, blue, sasha, tea|...]] .

答案 1 :(得分:2)

像这样吗?

 ?- test1(L), solution(L, S).
  L = [[spanish, white], [italian, white], [italian, red], [canadian, blue]],
  S = [[canadian, blue], [italian, red], [spanish, white]] ;
false.

?- test2(L), solution(L, S).
  L = [[spanish, white, 5], [italian, red, 4], [canadian, blue, 2], [canadian, red, 2], [spanish, blue, 4]],
  S = [[canadian, blue, 2], [italian, red, 4], [spanish, white, 5]] ;
false.

测试:

within ".mark-ready-btn.server-button" do
  click_on ".server-mark-ready"
end

这不是最佳的性能,因为在答案集中没有中间减少,但是可以很好地说明Prolog。