Search code examples
dictionaryprologkeyswi-prolog

Prolog: How to switch negative indexes of dictionary into positive successors of the maximal index?


I have some SWI-Prolog dictionary of following form:

dict_label{-N: a(-N), -N+1: a(-N+1), ..., -1: a(-1), 1: a(1), ..., M: a(M)}.

whereby:

  • a(j), -N≤j≤M are the values of the dictionary with keys in the integer interval [-N, M]\{0}.

My aim now is to convert this dictionary into some dictionary of form:

dict_label{1: a(1), ..., M: a(M), M+1: a(-N), ..., M+N: a(-1) }.

as example:

P = test_label{-5: e, -4: f, -3: g, -2: h, -1: i, 1: a, 2:b, 3: c, 4: d} 

should be converted into:

Q = test_label{1: a, 2: b, 3: c, 4: d, 5: e, 6: f, 7: g, 8: h, 9: i}

I hope you can help me to find some good way to solve the problem and find some predicate to switch negative index in that form.


Solution

  • The problem seems very specific, so I will share an ad-hoc solution to solve it.

    The solution requires the transformation of the dict into a list of ordered pairs to work on the keys of such pairs.

    The positive keys will remain unchanged while the negative keys will be modified: by using the fact that the list of keys is ordered this can be done by keeping a counter starting at M+1 and gradually updating the list of keys.

    Finally the keys are put together with the original values and the list of pairs is transformed again into a dictionary.

    This is the code:

    dict_normalize(DictIn, DictOut) :-
            dict_pairs(DictIn, Tag, Pairs), % transform dict into ordered list of pairs
            pairs_normalize(Pairs, NewPairs), % work on the pairs to get the new dict
            dict_pairs(DictOut, Tag, NewPairs).
    
    pairs_normalize(PairsIn, PairsOut) :-
            pairs_values(PairsIn, Values), % extract values
            pairs_keys(PairsIn, Keys), % extract keys
            keys_normalize(Keys, NewKeys), % work on the keys to get the new list of pairs
            pairs_keys_values(PairsOut, NewKeys, Values).
    
    keys_normalize(KeysIn, KeysOut) :-
            max_list(KeysIn, Max),
            Start is Max + 1, % determine the starting index for negative values
            keys_normalize(KeysIn, Start, KeysOut). % this predicate works because keys are known to be ordered
    
    keys_normalize([], _, []).
    keys_normalize([H|T], N, [N|NewT]) :- % negative key
            H < 0,
            !,
            NewN is N + 1,
            keys_normalize(T, NewN, NewT).
    keys_normalize([H|T], N, [H|NewT]) :- % positive key (unchanged)
            keys_normalize(T, N, NewT).
    
    

    Example:

    ?- P = test_label{-5: e, -4: f, -3: g, -2: h, -1: i, 1: a, 2:b, 3: c, 4: d},
    dict_normalize(P, Q).
    
    P = test_label{-5:e, -4:f, -3:g, -2:h, -1:i, 1:a, 2:b, 3:c, 4:d},
    Q = test_label{1:a, 2:b, 3:c, 4:d, 5:e, 6:f, 7:g, 8:h, 9:i}.