如何在prolog中制作一个特定长度的随机列表而不重复?

时间:2017-10-01 12:20:41

标签: prolog

我试图编写一个谓词randomnames/1,它生成一个包含三个不同名称的随机列表。名称在数据库中,我已经有一个随机名称的谓词:

name(1, Mary).
name(2, Pat).
name(3, James).
name(4, Bob).
name(5, Susan).

random_name(Name):- 
  random(0, 6, N),    
  name(N, Name). 

为了将其列入清单,有人建议我应该这样做:

random_names([A,B,C]) :-
    random_name(A),
    random_name(B),
    random_name(C).

唯一的问题是它可能会在生成的列表中获得重复项。我无法弄清楚如何解决这个问题。我可以编写一个新的谓词来删除重复项,但是如何用另一个变量替换副本呢,这样列表仍然有三个元素?当random_names谓词中没有清晰的头尾时,我怎么能写出删除谓词?

2 个答案:

答案 0 :(得分:3)

在Prolog中编程时,请考虑您的解决方案必须满足的条件

目前,您已经找到了如何描述包含三个元素的列表,其中每个元素都是一个随机名称。

这是一个好的开始,但还不够:此外,您现在想要描述元素成对不同的条件。

因此,请考虑如何描述三个元素的列表,其中所有元素都是成对不同的。

我给你一个开始,用dif/2以合理的方式表达术语的不平等(见):

three_distinct_elements([A,B,C]) :-
        dif(A, B),
        dif(A, C),
        dif(B, C).

您可以找到一种更通用,更优雅的方式来描述具有3个以上元素的列表。但是,上述内容足以解决手头的任务。

所以,它只是组合你已有的谓词,例如:

three_distinct_random_names(Ls) :-
        random_names(Ls),
        three_distinct_elements(Ls).

这只是您已经实施的条件的连接。总的来说,这个谓词的解决方案将为您提供所需的内容:一个包含三个不同随机名称的列表。

但是,谓词也可能失败(练习:为什么?)。

要尝试谓词,直到找到解决方案,请使用例如repeat/0

?- repeat, three_distinct_random_names(Ls).

还有更好的方法来解决这个问题。但是,作为第一个近似值,我建议关注好的构建块,描述您想要满足的条件。

我对你写的内容有一般性评论:

  

我可以为删除重复项编写一个新的谓词,但是我如何用另一个变量替换副本,那么列表仍然有三个元素?

所有措辞都非常命令式:你在这里想到“删除”,“替代”等。为了充分利用Prolog,请关注描述条件对于您想要找到的解决方案,必须持有

您想要找到没有重复的列表吗? 描述这样的列表必须是什么样子。你想要随机名字吗? 描述这样的名字等等。

答案 1 :(得分:0)

如果您使用Swi-Prolog,您可以使用与Swi捆绑在一起的非常方便的randseq / 3谓词。 randseq / 3生成所有不同随机数的列表,范围从1到N.生成此列表后,剩下的就是将数字映射到名称:

name(1, 'Mary').
name(2, 'Pat').
name(3, 'James').
name(4, 'Bob').
name(5, 'Susan').

random_names(Names, Count) :-
    % 5 is the amount of names available in database
    randseq(Count, 5, L),
    maplist(name, L, Names).

用法示例:

?- random_names(Names, 3).
Names = ['Mary', 'James', 'Susan'].

?- random_names(Names, 5).
Names = ['Susan', 'Bob', 'James', 'Mary', 'Pat'].