【问题标题】:How to make a random list of a specific length without duplicates in prolog?如何在序言中制作一个特定长度的随机列表而不重复?
【发布时间】:2017-10-01 12:20:40
【问题描述】:

我正在尝试编写一个谓词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 谓词中没有明确的头尾时,我什至如何编写删除谓词?

【问题讨论】:

    标签: prolog


    【解决方案1】:

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

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

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

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

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

    three_distinct_elements([A,B,C]) :- 差异(A,B), 差异(A,C), 差异(B,C)。

    对于包含 3 个以上元素的列表,您可能会找到一种更通用、更优雅的方式来描述这一点。但是,以上足以解决手头的任务。

    所以,它只剩下组合你已经拥有的谓词,例如:

    three_distinct_random_names(Ls) :- 随机名称(Ls), 三个不同的元素(Ls)。

    这只是您已经实现的条件的合取。总的来说,这个谓词的解决方案会给你你想要的:一个包含三个不同随机名称的列表。

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

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

    ?- 重复,三个_distinct_random_names(Ls)。

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

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

    我可以为删除重复项编写一个新谓词,但是我如何用另一个变量替换重复项,以便列表仍然包含三个元素?

    这一切的措辞都非常必要:您在这里考虑“删除”、“替换”等。要充分利用 Prolog,请专注于描述条件对于您想要找到的解决方案,必须持有

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

    【讨论】:

    • 非常感谢您的详尽回答!至于谓词为什么会失败,我的猜测是,如果实际上找到了重复项,dif 之一将失败,然后three_distinct_elements 失败,然后整个谓词失败。对吗?
    • 你认为你的代码有可能只得到一个不会失败的答案吗?我需要这个谓词作为另一个谓词的一部分,所以我不能在查询中做repeat。在代码中添加repeat 会给我很多回溯结果,添加cut 似乎否定repeat。是否可以同时进行重复和剪切?
    • 避免!/0,使用once((repeat,...))
    • 我一直在尝试做一次((重复,))一段时间,但无论我尝试什么,我仍然无法让代码不失败。有什么建议吗?
    • 我的意思是使用once((repeat,three_distinct_random_names(Ls)))。重复此过程,直到找到解决方案,然后提交到第一个解决方案。最好使用once/1,因为它的效果更局部。
    【解决方案2】:

    如果您使用的是 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'].
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-04-01
      • 2021-10-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-09-01
      • 1970-01-01
      相关资源
      最近更新 更多