2
votes

I need to write the include_assoc / 3 predicate that filters the associative array (second argument) with the given predicate (first argument) and writes the result to the third argument. The predicate should work analogously to include / 3. The filter predicate should use a key-value pair as argument.

I can't change the table into a list before filtering. How can i do it?

My code

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)).
1
Please share your attempt with us and we will help you get unstuck.Daniel Lyons
@Daniel Lyons i have pasted coderestarcik
What's Wynik?Daniel Lyons
@DanielLyons Oh sorry, i had there other names of variables in my oryginall code, but now I introduced some changes and looks like it is workingrestarcik

1 Answers

0
votes

The easiest solution would be to convert this to a list, filter the list with the predicate, and then construct a new assoc.

:- 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).

You apparently cannot do this. But you still need a way to iterate all the items of the assoc without entering a failure-driven loop which will undo your bindings after each fail. gen_assoc will give you all the keys, but you'll either have to use findall/3 (making it the same as converting it to a list) or you'll have to fail after each binding (undoing your work).

Another approach here is to get the list of keys only, and then use the removal predicate to get rid of values when they don't match the filter. First we need to get the keys and then call a helper predicate to walk the list of keys:

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

Now we can retrieve the current key/value (the head of the keys list) and then call your filter predicate to check it. If it passes, we just recur; if it fails, we remove it and pass the result of removing it into the recursive step.

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)
    ).

When we run out of keys, the input is the output:

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

I don't know if this fulfills your criteria or not, but I hope it does.