Prolog: Convert list into dictionary? - list

I am searching some swi-prolog predicate:
list_to_dict(List, Dict) :- ??
Which is able to convert a list like
l = [a, b, c, d]
into a Prolog dict d whose keys are equal to the list indexes starting at 1. In this example above d is of form:
d = dict_label{1:a,2:b,3:c,4:d}
I would appreciate, if you can help me to find some general and hopefully short solution of that problem.

You can use the following predicate:
% list_to_dict(+Values, +Tag, -Dict)
list_to_dict(Values, Tag, Dict) :-
findall(Key-Value, nth1(Key, Values, Value), Pairs),
dict_create(Dict, Tag, Pairs).
Example:
?- list_to_dict([a,b,c,d], dict_label, Dict).
Dict = dict_label{1:a, 2:b, 3:c, 4:d}.

Related

Write a predicate called rlen(X,N) to be true when N counts the total number of occurrences of atoms in the list X

I want to get this solution for my question. For example, ?- rlen([a,[a,b],c],X). returns X = 4. I tried the following code but it returns answer 3. Maybe, it's taking [a,b] as one element. I am new to prolog and learning, any help would be really appreciated.
rlen([],0).
rlen([_|T],N) :- rlen(T,N1),N is N1+1.
The code you wrote returns the number of elements in a list and [a,[a,b],c] has exactly 3 elements: a, [a,b] and c. If you want to do a nested count, I would suggest using the build-in predicate flatten/2 to flatten the list.
example (tested with SWISH):
?- rlen([a,[a,b],c],X).
X = 3.
?- flatten([a,[a,b],c],L).
L = [a, a, b, c].
?- flatten([a,[a,b],c],L), rlen(L,N).
L = [a, a, b, c],
N = 4.
However not using inbuild predicates is a bit more challenging, because you have to go through your list like in any normal length predicate, and for every Head element you have to distinguish between the case that the head element is a list or is not a list. If A is a list, count the elements of A, otherwise just add 1. (a -> b ; c ) is an if-then else: if a, then b, else c. Tested with SWISH:
rlen([],0).
rlen([A|T],N) :-
( is_list(A)
-> rlen(A,NA)
; NA is 1
),
rlen(T,NT),
N is NA+NT.
?- rlen([a,[a,b],c],X).
X = 4.

Change list of variables according to another list containing the index and atoms in prolog

I have a list of variables E and a list L and I want a predicate that works like this:
E=[A,B,C,D]
L=[(1,b),(3,m)]
solve(E,L).
E=[b,B,m,D]
Basically solve() should run through the list L and change E by using (a,b) to unify the variable at index a with the atom B. Is there any way to do this?
The meaning of the (badly named) solve/2 predicate is something like "for every pair (Index, Element), the Index-th element of the input list is Element". You are likely using a Prolog implementation that already has a predicate called something like nth1/3 which expresses "the Index-th element of List is Element". For example, in SWI-Prolog:
?- List = [A, B, C, D], nth1(3, List, this_is_the_third_element).
List = [A, B, this_is_the_third_element, D],
C = this_is_the_third_element.
So an alternative implementation of your predicate simply calls nth1/3 for each of your (Index, Element) pairs:
solve(_List, []).
solve(List, [(Index, Elem) | Pairs]) :-
nth1(Index, List, Elem),
solve(List, Pairs).
And with this you're done:
?- E = [A, B, C, D], L = [(1, b), (3, m)], solve(E, L).
E = [b, B, m, D],
A = b,
C = m,
L = [(1, b), (3, m)] ;
false.
Note that this solution is simple, but it has quadratic complexity in the length of the input list: nth1/3 might have to visit the entire N-element list N times. In the unlikely case that you need this predicate for a performance-critical part of some larger program, consider the more optimized solution sketched in the other answer.
Is there any way to do this?
Certainly. And as they say in Perl: "There is more than one way to do it".
Couple of problems:
Do not use (1,b). Use the idiomatic -(1,b) instead, which is written as 1-b (the pair). This gives you a list of pairs: L=[1-b,3-m]. There is a library specifically dealing with such pairs: https://www.swi-prolog.org/pldoc/man?section=pairs - alternatively you can use real maps implemented with AVL trees: https://www.swi-prolog.org/pldoc/man?section=assoc
Now you just need to:
sort the list of pairs, probably using keysort: https://www.swi-prolog.org/pldoc/doc_for?object=sort/2 or https://www.swi-prolog.org/pldoc/doc_for?object=sort/4
Go through the list left to right, keeping the current index, and performing a replacement when the next key in your sorted list is hit, or just retaining the existing term from the list otherwise. The result goes into an accumulator variable as head of a list.
Done! Special handling of out-of-bounds indexes etc. to be suitably handled by throwing or failing.
How to go through the sorted list of pairs (I didn not test this!):
% case of Index hit:
go_through([Index-Value|Rest],Index,InList,OutList) :-
InList = [I|Rest],
OutList = [Value|More],
succ(Index,NextIndex),
go_through(Rest,NextIndex,Rest,More).
% case of Index miss:
go_through([NotYetIndex-Value|Rest],Index,InList,OutList) :-
NotYetIndex > Index, % that should be the case
InList = [I|Rest],
OutList = [I|More],
succ(Index,NextIndex),
go_through(Rest,NextIndex,Rest,More).
go_through([],_,L,L). % DONE
Alternatively, you can write a replace0 that replaces-by-index in a list, and go through the L list.
Addendum: Working code using go_through
Actually contains a few subtlties
another_vectorial_replace1(ListIn,ReplacePairs,ListOut) :-
maplist([_,_]>>true,ListIn,ListOut), % Bonus code: This "makes sure" (i.e. fails if not)
% that ListIn and ListOut are the same length
maplist([(A,B),A-B]>>true,ReplacePairs,RealPairs), % Transform all (1,b) into [1,b]
maplist([K-_]>>integer(K),RealPairs), % Make sure the RealPairs all have integers on first place
keysort(RealPairs,RealPairsSorted), % Sorting by key, which are integers; dups are not removed!
debug(topic,"ListIn: ~q",[ListIn]),
debug(topic,"RealPairsSorted: ~q",[RealPairsSorted]),
go_through(RealPairsSorted,1,ListIn,ListOut),
debug(topic,"ListOut: ~q",[ListOut]).
% Case of Index hit, CurIndex is found in the first "Replacement Pair"
go_through([CurIndex-Value|RestPairs],CurIndex,ListIn,ListOut) :-
!, % Commit to choice
ListIn = [_|Rest],
ListOut = [Value|More],
succ(CurIndex,NextIndex),
go_through(RestPairs,NextIndex,Rest,More).
% Case of Index miss:
go_through([NotYetIndex-V|RestPairs],CurIndex,ListIn,ListOut) :-
NotYetIndex > CurIndex, % that should be the case because of sorting; fail if not
!, % Commit to choice
ListIn = [X|Rest],
ListOut = [X|More],
succ(CurIndex,NextIndex),
go_through([NotYetIndex-V|RestPairs],NextIndex,Rest,More).
% Case of DONE with list traversal
% Only succeed if there are not more pairs left (i.e. no out-of-bound replacements)
go_through([],_CurIndex,L,L).
% ===
% Tests
% ===
:- begin_tests(another_vectorial_replace1).
test(empty) :- another_vectorial_replace1([],[],LO),
LO=[].
test(nop_op) :- another_vectorial_replace1([a,b,c,d],[],LO),
LO=[a,b,c,d].
test(one) :- another_vectorial_replace1([a],[(1,xxx)],LO),
LO=[xxx].
test(two) :- another_vectorial_replace1([a,b,c,d],[(4,y),(2,x)],LO),
LO=[a,x,c,y].
test(full) :- another_vectorial_replace1([a,b,c,d],[(1,e),(2,f),(3,g),(4,h)],LO),
LO=[e,f,g,h].
test(duplicate_replacement,[fail]) :- another_vectorial_replace1([a],[(1,x),(1,y)],_).
test(out_of_bounds_high,[fail]) :- another_vectorial_replace1([a],[(2,y)],_).
test(out_of_bounds_low,[fail]) :- another_vectorial_replace1([a],[(0,y)],_).
:- end_tests(another_vectorial_replace1).
rt :- debug(topic),run_tests(another_vectorial_replace1).
Addendum 2
Replacement using maplist/N, foldl/N and library(assoc)
Recursive calls disappear behind the curtain!
https://github.com/dtonhofer/prolog_notes/blob/master/code/vector_replace0.pl
(the following assumes that the indices in the pairs list will be sorted, in increasing order, as the example in the question indicates.)
What you said can be written as one conjunction
E=[A,B,C,D], L=[(1,a),(3,c)], solve(E,L), E=[a,B,c,D].
which you intend to be holding under the proper definition of solve/2 that you seek to find. But isn't it like saying
E=[A|E2], L=[(1,a)|L2],
E2=[B,C,D], L2=[(3,c)],
solve(E2,L2), E2=[B,c,D],
E=[a|E2].
? Although, something doesn't quite fit right, here. c in E2 appears in second position, not 3rd as indicated by its entry in L2.
But naturally, L2 must be indexed from 2, since it is a tail of L which is indexed from 1. So we must make this explicit:
E=[A,B,C,D], L=[(1,a),(3,c)], solve(E,L), E=[a,B,c,D]
==
E=[A,B,C,D], L=[(1,a),(3,c)], solve(E,1,L), E=[a,B,c,D] % starting index 1
==
E=[A|E2], L=[(1,a)|L2],
E2=[B,C,D], L2=[(3,c)],
solve(E2,2,L2), E2=[B,c,D], E=[a|E2]
must, and now can, hold. But where did a get from, in E? What we actually mean here is
E=[A|E2], L=[(1,a)|L2],
p( (1,a), 1, a), % index match
E2=[B,C,D], L2=[(3,c)],
solve(E2,2,L2), E2=[B,c,D], % starting index 2
E=[a|E2]
with p/3 defined as
p( (I,A), I, A).
And so it must also hold that
E2=[B|E3], L2=[(3,c)],
\+ p( (3,c), 2, c), % index mismatch
E3=[C,D], L3=L2,
solve(E3,3,L3), E3=[c,D], E2=[B|E3]
L2 is not traversed along at this step (L3=L2), since p( (3,c), 2, c) does not hold.
Do you see how the recursive definition of solve/3 reveals itself here? Could you finish it up?

Print a List inside a nested List that contains an element

I have the following problem.
I'm given a listOfLists, a value (row,col) and I need to get the list inside a list that contains that certain value, up to my value's index inside that list.
For example
?- find_list([[(1,2),(1,3),(1,4)], [(2,2),(2,3),(2,4)]], (1,3), List2).
List2 = [(1,2),(1,3)].
My problem is that if I use member/2 I will only get true or false for if my value is inside listOfList or not, and not the list that I will need to be working with.
How can I get that list that has my value inside it?
Does it matter that the values are two-dimensional coordinates? Is there an ordering on them that you must respect, or is it simply the ordering of the elements in the list? I will assume the latter.
If you want to split a list at some point, the standard append/3 predicate is usually the way to go. For example, assume we want to cut the list [a, b, c, d, e] into a prefix containing the elements before c and a suffix containing the elements after c. Here is how that is done:
?- append(Prefix, [c | Suffix], [a, b, c, d, e]).
Prefix = [a, b],
Suffix = [d, e] ;
false.
Here c is excluded from the prefix, but that's easy to fix:
?- append(Prefix, [c | Suffix], [a, b, c, d, e]), append(Prefix, [c], UpToAndIncludingC).
Prefix = [a, b],
Suffix = [d, e],
UpToAndIncludingC = [a, b, c] ;
false.
We can give this predicate a nice name:
list_pivot_prefix(List, Pivot, Prefix) :-
append(Prefix0, [Pivot | _Suffix], List),
append(Prefix0, [Pivot], Prefix).
And your find_list/3 predicate then simply finds all the lists in the given list of lists for which this relation holds:
find_list(Lists, Element, Prefix) :-
member(List, Lists),
list_pivot_prefix(List, Element, Prefix).
Here is your test case:
?- find_list([[(1,2),(1,3),(1,4)],[(2,2),(2,3),(2,4)]],(1,3),List2).
List2 = [ (1, 2), (1, 3)] ;
false.

Prolog Convert a list in a list of lists

I need to convert a list of elements into a list of lists.
For example, if i have the list [1,2,3,4] the output must be [[1],[2],[3],[4]], one element per list.
create([],_, _, _).
create([H|T], Aux, X, Result) :-
append([H], Aux, X),
Result = [X],
create(T, X, _, Result).
I always get false... is this even possible to do?
Another possibility to define this relation is by using DCGs. They yield easily readable code when describing lists. Let's stick with the name singletons as suggested by #false in the comments:
singletons([]) --> % the empty list
[]. % is empty
singletons([H|T]) --> % the head of a nonempty list
[[H]], % is a list on its own
singletons(T). % and so is the tail
You can query this directly with phrase/2:
?- phrase(singletons([1,2,3,4]),X).
X = [[1],[2],[3],[4]]
Or write a wrapper-predicate with phrase/2 as the single goal:
singletons(L,Ls) :-
phrase(singletons(L),Ls).
And query that:
?- singletons([1,2,3,4],Ls).
Ls = [[1],[2],[3],[4]]
The predicate also works the other way around:
?- singletons(L,[[1],[2],[3],[4]]).
L = [1,2,3,4] ? ;
no
As well as the most general query:
?- singletons(L,Ls).
L = Ls = [] ? ;
L = [_A],
Ls = [[_A]] ? ;
L = [_A,_B],
Ls = [[_A],[_B]] ?
...
Alternatively you can also define a simple predicate that describes a relation between an arbitrary element and itself in brackets and then use maplist/3 from library(apply) to apply it on every element of a list:
:- use_module(library(apply)).
embraced(X,[X]).
singletons(L,Ls) :-
maplist(embraced,L,Ls).
This version yields the same results for the above queries. However, it is more efficient. To see that consider the following query from above:
?- singletons(L,[[1],[2],[3],[4]]).
L = [1,2,3,4]
Above you had to enter ; to make Prolog search for further solutions and subsequently fail (indicated by no). With this version there are no unnecessary choice points left and Prolog is succeeding deterministically for the query.
Try this
create([],[]).
create([H|T],[[H]|T2]):- create(T,T2).
I tried
?- create([1,2,3,4],X).
and the result was
X = [[1], [2], [3], [4]].

creating a shallow binary predicate in Prolog to replace all the number in a list by atom 'number'

I am trying to create a deep binary predicate text/2 which will process a list and replace each number in a list by the atom number.
Example:
?- text([a,[[13]],b,14,c(5),8], Xs).
Xs = [a,[[number]],b,number,c(5),number].
Solution:
I tried doing it as below but getting
Warning: Attempt to read past end of file in SGETTOK
The code is:
toNumber(In,number) :-
number(In),
!.
toNumber(In,In).
maplist(_,[],[]).
maplist(Pred,[InListHead|InListTail],[OutListHead|OutListTail]) :-
Term = [Pred,InListHead,OutListHead],
call(Term),
maplist(Pred,InListHead,OutListHEad).
text(InListHead,OutListHead) :-
maplist(toNumber,InListHead,OutListHead).
You could use the following:
text(List,New):-
maplist(item_replace,List,New).
item_replace(Item,number):-
number(Item).
item_replace(Item,Item).
Q:
?- text([a,[[13]],b,14,c(5),8], Xs).
Xs = [a, [[13]], b, number, c(5), number] .
This will backtrack to other answers you may not want though. So you could add a cut.
item_replace(Item,number):-
number(Item),!.
item_replace(Item,Item).
or
item_replace(Item,number):-
number(Item).
item_replace(Item,Item):-
\+number(Item).
Another method trying to use some logical purity predicates..
is_number(L,T):-
number(L)->
T =true;T=false.
item_replace(Item,Number):-
if_(is_number(Item),Number=number,Number=Item).
text_2(List,New):-
maplist(item_replace,List,New).
Q:
?-text([a,[[13]],b,14,c(5),8], Xs).
Xs = [a, [[13]], b, number, c(5), number].