2

我需要编写 include_assoc / 3 谓词,用给定的谓词(第一个参数)过滤关联数组(第二个参数)并将结果写入第三个参数。谓词应该类似于包含 / 3。过滤谓词应该使用键值对作为参数。

我无法在过滤之前将表格更改为列表。我该怎么做?

我的代码

include_assoc(_,X,_):-
    empty_assoc(X),!.
include_assoc(Filtr,Tab,Result):-
    min_assoc(Tab,Key,Value),
    del_min_assoc(Tab,_,_,Tab1),
    (call(Filtr,Key-Value) -> 
    (include_assoc(Filtr,Tab1,Result1),
    put_assoc(Key,Result1,Value,Result));
    include_assoc(Filtr,Tab1,Result1)).
4

1 回答 1

0

最简单的解决方案是将其转换为列表,使用谓词过滤列表,然后构造一个新的关联。

:- use_module(library(assoc)).
:- use_module(library(apply)).

filter_assoc_l(Filter, In, Out) :-
    assoc_to_list(In, List),
    include(Filter, List, OutList),
    list_to_assoc(OutList, Out).

你显然不能这样做。但是您仍然需要一种方法来迭代 assoc 的所有项目,而无需进入失败驱动的循环,该循环将在每次失败后撤消您的绑定。gen_assoc将为您提供所有密钥,但您要么必须使用findall/3(使其与将其转换为列表相同),要么在每次绑定后都必须失败(撤消您的工作)。

这里的另一种方法是仅获取列表,然后在值与过滤器不匹配时使用删除谓词删除它们。首先,我们需要获取键,然后调用辅助谓词来遍历键列表:

filter_assoc_unlist(Filter, In, Out) :-
    assoc_to_keys(In, Keys),
    filter_assoc_keys(Filter, In, Keys, Out).

现在我们可以检索当前的键/值(键列表的头部),然后调用您的过滤谓词来检查它。如果它通过了,我们只是重复;如果失败,我们将其删除并将删除的结果传递给递归步骤。

filter_assoc_keys(Filter, In, [Key|Keys], Out) :-
    min_assoc(In, Key, Value),
    (call(Filter, Key-Value) ->
        filter_assoc_keys(Filter, In, Keys, Out)
    ;
        del_assoc(Key, In, _, Next),
        filter_assoc_keys(Filter, Next, Keys, Out)
    ).

当我们用完键时,输入就是输出:

filter_assoc_keys(_, Out, [], Out).

我不知道这是否符合您的标准,但我希望它符合。

于 2019-11-26T18:13:41.073 回答