如何在prolog中创建特定长度的随机列表而不重复?

如何在prolog中创建特定长度的随机列表而不重复?,prolog,prolog-dif,Prolog,Prolog Dif,我正在尝试编写一个谓词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]) :-

我正在尝试编写一个谓词
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\u name
谓词中没有清晰的头尾时,我甚至如何编写remove谓词?

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

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

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

因此,考虑如何描述一个包含三个元素的列表,其中所有元素都是两两不同的

首先,使用
dif/2
以合理的方式表达术语的质量(请参阅):

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

我对你写的东西有一个一般性的评论:

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

所有这些都是非常必要的:您在这里考虑“删除”、“替换”等。为了最大限度地利用Prolog,请关注描述对于您想要找到的解决方案必须满足的条件


你想找到一个没有重复项的列表吗?描述这样一个列表应该是什么样子。你想要随机的名字?描述这样的名称是什么样子,等等。

如果您使用的是Swi Prolog,您可以使用非常方便的randseq/3谓词,它与Swi捆绑在一起。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'].

非常感谢您详尽的回答!至于谓词失败的原因,我的猜测是,如果事实上发现了重复项,那么
dif
中的一个将失败,然后
三个不同元素
失败,然后整个谓词失败。是吗?你认为你的代码有可能只得到一个不会失败的答案吗?我需要这个谓词作为另一个谓词的一部分,因此我无法在查询中执行
repeat
。在代码中添加
repeat
会得到很多回溯结果,添加
cut
似乎会否定
repeat
。是否可以同时进行重复和剪切?避免
/0,使用
一次((重复,…)
!我已经试着做了一次((重复,))有一段时间了,但是无论我做什么,我仍然无法让代码不失败。有什么建议吗?我的意思是使用
一次((重复,三个不同的随机名称(Ls))
。这会重复,直到有解决方案,然后提交到第一个解决方案。最好使用
一次/1
,因为它的效果更局部。 ?- repeat, three_distinct_random_names(Ls).
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'].