首页 > 解决方案 > 在 Prolog 中解析列表列表

问题描述

我是新手Prolog。考虑以下示例:

MainList =  [["A","a","0"],["A","b","0"],["B","a","0"],["B","b","0"],["A","a","1"],["B","b","1"],["C","c","1"],["C","a","0"]]
SubList = ["A","b","-']

格式MainList:第一个索引应该是大写字母,第二个索引应该是小写字母,第三个索引应该是数字。MainList可以包含其他格式(和长度),但我选择这种格式是因为它更容易解释。我只是想解释一下,每个子列表的索引都分为几类——每个列表的第一个元素属于category1,第二个元素category2,依此类推。该"-"符号表示我们确实知道该元素与其他元素的结合。

我想创建的关系应该通过MainList并删除所有不遵循的子列表SubList。对于上面的示例,它应该返回:

Output =  [["A","b","0"],["B","a","0"],["C","c","1"],["C","a","0"]]

说明:"A"正在与"b"包含这些元素之一的每个子列表一起工作,应该检查。如果它们都存在,那么没关系(没有重复)。否则如果只有其中一个存在,那就不行了,我们不应该把它插入到Output列表中。

另一个例子(MainList与之前的有点不同):

MainList =  [["A","a","0"],["A","b","0"],["B","a","0"],["B","b","0"],["A","b","1"],["B","b","1"],["C","c","1"],["C","a","0"]]
SubList = ["C","a","0"]
Output = [["A","b","1"],["B","b","1"],["C","a","0"]]

我确实理解算法 - 我们应该检查每个子列表MainList并检查输入子列表的连接是否正常,如果是,我们会将其插入Output列表中。问题是,我不明白如何正确实施它。如果子列表包含多个2连接(如第二个示例所示)怎么办?我应该如何区别对待子列表?

编辑:我会尝试解释更多。每个元素的位置很重要。每个地方代表一个不同的类别。例如,第一位可能代表大写字母,第二位代表小写字母,第三位代表数字(可能有更多类别)。我们得到一个sublist代表两个或多个元素之间的键。例如,我们在"A""b":之间建立了联系["A","b","-"]。我们应该遍历 的子列表MainList并检查这些子列表中的每一个是否包含这些元素之一("A""b")。如果是这样,我们应该检查绑定是否正确。例如,如果我们有一个子列表A(当然在第一个索引中),那么我们应该转到第二个索引并检查是否"b"在那儿。如果它不存在,我们不应该将它插入到Output列表中,否则我们将插入。例如,我们有一个债券["A","b","-"],我们进入了一个子列表,MainList其如下所示:["A","a","0"]["B","b","2"]。我们不会将这些列表惰性化到Output. 但是,如果我们得到子列表,例如:并且["A","b","1"]我们会将这些列表插入到.["A","b","2"]["B","a","1"]Output

标签: prolog

解决方案


对于你给出的例子,我写了一个满足输出条件的代码,但没有尝试其他情况,也没有考虑代码的效率,所以你可以改进它。这是代码:

subList(List,SubL,Out):-
    (member("-",SubL),
     select("-",SubL,SubRem)
    ;
    \+ member("-",SubL),
    SubRem = SubL),
    findall(L,((member(L,List),checkEq(SubRem,L));
           (member(L,List),checkNeq(SubRem,L))),Out).

checkEq([],_).
checkEq([S|Rest],[E|List]):-
    S == E,
    checkEq(Rest,List).

checkNeq([],_).
checkNeq([S|Rest],List) :-
    \+ member(S,List),
    checkNeq(Rest,List).

说明:我所做的是,首先我从子数组(如果存在)中删除了“-”字符,以使计算更容易。然后,我要么检查 SubList 中的每个元素与MainList的选定子列表的元素是否有序条件。如果失败,我会检查SubList的任何元素是否都不包含在选定的子列表中。如果两项检查均失败,我将转到下一个子列表。使用 findall/3 谓词,我找到满足其中任何一个条件的所有组合并将它们分组到列表Out

checkEq编辑:为谓词添加附加子句:

checkEq([S|Rest],[E|List]):-
    S \= E,
    member(S,List),
    checkEq([S|Rest],List).

所以最终版本是:

checkEq([],_).
checkEq([S|Rest],[E|List]):-
    S == E,
    checkEq(Rest,List).

checkEq([S|Rest],[E|List]):-
    S \= E,
    member(S,List),
    checkEq([S|Rest],List).

推荐阅读