Flattening only one level of a list in Prolog - list

I'm working on a problem to flatten only one level of a list in Prolog. For example, [[1],[2,3]] would become [1,2,3], but [[1,[2]],3] would only flatten down to [1,[2],3]. I went through some other questions on the site, but none thoroughly answered this question, and I just can't get my code to work on all my test cases.
Update: the code works! Here is the eventual answer that I came to:
my_flatten([], []).
my_flatten([A|B],L) :- is_list(A), my_flatten(B,B1), !, append(A,B1,L).
my_flatten([A|B],[A|B1]) :- my_flatten(B,B1).

You need 3 simple clauses, I will show just the most complex one
flat([H|T],R) :- is_list(H), flat(T,T1), append(H,T1,R).
other two clauses are the base recursion case, and a copy as is of head to result.
You should also place a cut in the clause I've shown, otherwise on backtracking you'll get wrong results (due to firing of the clause copy as is)

This are the results obtained with the predicate described at the bottom. With flat_lvl predicate u can specify the desired level for flat a list.
Examples:
% Lis= [[e1, e2, [e31, e32]], [e4, e5, e6, e7], [e8, e9]],
% flat_lvl(Lis, FlatLis, 2).
%
% ---> FlatLis = [e1, e2, e3, e4, e5, e6, e7, e8, e9]
% Lis= [[e1, e2, [e31, e32]], [e4, e5, e6, e7], [e8, e9]],
% flat_lvl(Lis, FlatLis, 1).
%
% ---> FlatLis = [e1, e2, [e31, e32], e4, e5, e6, e7, e8, e9]
% Lis= [[e1, e2, [e31, e32]], [e4, e5, e6, e7], [e8, e9]],
% flat_lvl(Lis, FlatLis, 0).
%
% ---> FlatLis = [[e1, e2, [e31, e32]], [e4, e5, e6, e7], [e8, e9]]
The predicate to flat a list with a specified level is the following, so just set DeepLvl to 1:
flat_lvl([],[],_).
flat_lvl([LisH| LisT], FlatLis, DeepLvl):-
Lvl is DeepLvl - 1, Lvl >= -1,
(flat_lvl(LisH, FlatH, Lvl); FlatH= [LisH]),
flat_lvl(LisT, FlatTail, DeepLvl),
append(FlatH, FlatTail, FlatLis), !.
?- flat_lvl(List, 1).

Related

Listing elemets of a list as i want, in Prolog

This is my list in Prolog:
myList([a,b,c,d,e]).
I am trying to write a predicate. That predicate should give me this result:
ab
ac
ad
ae
bc
bd
be
cd
ce
de
I found a solution that's near to my goal. But it is not exactly what I want.
?- L=[a,b,c], findall(foo(X,Y), (member(X,L),member(Y,L)), R).
L = [a, b, c],
R = [foo(a, a), foo(a, b), foo(a, c), foo(b, a), foo(b, b), foo(b, c), foo(c, a), foo(c, b), foo(..., ...)].
For example i dont want to aa or bb or cc. Also, there is already ac result. So i dont want to again ca.
Sorry for my English.
Thanks.
?- set_prolog_flag(double_quotes, chars).
true.
?- List = "abcde",
bagof(X-Y, Pre^Ys^( append(Pre, [X|Ys], List), member(Y,Ys) ), XYs).
List = "abcde", XYs = [a-b,a-c,a-d,a-e,b-c,b-d,b-e,c-d,c-e,d-e].
?- List = [A,B,C,D,E],
bagof(X-Y, Pre^Ys^( append(Pre, [X|Ys], List), member(Y,Ys) ), XYs).
List = [A,B,C,D,E], XYs = [A-B,A-C,A-D,A-E,B-C,B-D,B-E,C-D,C-E,D-E].
From your question it is not that evident what you want but it seems you are happy to use findall/3. Above solutions use bagof/3 which is a somewhat more civilized version of findall/3. bagof/3 takes into account variables, and thus you get the same result with concrete characters [a,b,c,d,e] or with a list of variables [A,B,C,D,E].
You have used terms foo(a,b), in such situations it is more common (and convenient) to say a-b.
Here is another solution that does not need any of the higher-order predicates.
:- set_prolog_flag(double_quotes, chars).
:- use_module(library(double_quotes)).
list_pairwise([], []).
list_pairwise([E|Es], Fs0) :-
phrase(values_key(Es, E), Fs0,Fs),
list_pairwise(Es, Fs).
values_key([], _K) --> [].
values_key([V|Vs], K) -->
[K-V],
values_key(Vs, K).
?- list_pairwise("abcde", KVs).
KVs = [a-b,a-c,a-d,a-e,b-c,b-d,b-e,c-d,c-e,d-e].
?- list_pairwise(L, [a-b,a-c,a-d,a-e,b-c,b-d,b-e,c-d,c-e,d-e]).
L = "abcde"
; false.
?- list_pairwise(L, [A-B,A-C,A-D,A-E,B-C,B-D,B-E,C-D,C-E,D-E]).
L = [A,B,C,D,E]
; false.
?- KVs = [K1-_,K1-_,K2-_|_], dif(K1,K2), list_pairwise(Ks,KVs).
KVs = [K1-K2,K1-_A,K2-_A], Ks = [K1,K2,_A], dif:dif(K1,K2)
; false.
In the last query we show that a sequence starting with keys, K1, K1, K2 can only result in the sequence of three elements.
What about a couple of predicates as follows ?
printCouples(_, []).
printCouples(E1, [E2 | T]) :-
write(E1), write(E2), nl,
printCouples(E1, T).
printList([]).
printList([H | T]) :-
printCouples(H, T),
printList(T).
From
printList([a, b, c, d])
you get
ab
ac
ad
bc
bd
cd

replacing each element of a list by a specific list

I try to define replaceEltByclass(E1:list,E2:list) E is a list without sublist. each element of E1 belonging to a class C is replaced by the
elements of C. The final result is put in E2. For example, the goal rep_class([e1,e4,e6,e11], E2) will provide the list E2 : [[e1,e8,e10], e4,[e3,e6,e7],e11]. I don't have the good results.
/*The code*/
/*facts*/
class(c1,[e3, e6, e7]).
class(c2,[e1, e8, e10]).
/*rules*/
rep_class([],[]).
rep_class([E|Q],E2) :-
class(C,L),
not(member(E,L)),
concat(E2,E,E2),
rep_class(Q,E2).
rep_class([E|Q],E2) :-
class(C,L),
member(E,L),
concat(E2,L,E2),
rep_class(Q,E2).
/*conventional concat*/
concat([],L,L).
concat([H|T],L,[H|Res]) :- concat(T,L,Res).
The problem is in: class(C,L),not(member(E,L)), because it will give two solution one if C=C2 and then for example e1 belongs in C2 so it will replace it with L and one solution when C=C1 where it will leave it as e1. You need to write "does C exists such member(e1,L)??" so you have to collect all possible lists and see if member(e1,L) stands for a list L. So with some changes my version is :
class(c1,[e3, e6, e7]).
class(c2,[e1, e8, e10]).
rep_class([],[]).
rep_class([E|Q],[E|E2]) :-
findall(L,class(_,L),List),
not(find(List,E,_)),
rep_class(Q,E2).
rep_class([E|Q],[Lout|E2]) :-
findall(L,class(_,L),List),
find(List,E,Lout),
rep_class(Q,E2).
find([Lin|_],E,Lin):-member(E,Lin).
find([Lin|T],E,Lout):-not(member(E,Lin)),find(T,E,Lout).
As an example:
?- rep_class([e1,e4,e6,e11], E2).
E2 = [[e1, e8, e10], e4, [e3, e6, e7], e11] ;
false.

Swapping elements based on index given from another list

Hello my task is to swap elements of list, with the index that needs to be swapped in another list, so fx:
If I have:
[3,1,2] as the list
And:
[[1,2],[2,3]] as the index that needs to be swapped
Then it should go like:
[1,2] = 3 and 1 getting swapped
[2,3] = 3 and 2 getting swapped
So i would end up with Output = [1,2,3]
The predicate is specified to be like this:
swap(C,Input,Output)
Where C is the list of which elemenst that should be swapped.
Input is the list that should be swapped.
Output is the swapped list.
I would like some advice on how to swapping those elements based on this, I have already looked at this: swap two elements from list with specified indices
Hope that someone can help me with this.
Edit:
So far I have tried something like this:
swap( Input,[I|J], Input ) :-
I = J.
swap( Input, [I|J], Output ) :-
swap( Input, [I|J], Output, _, _ ).
swap( Input, [I|J], Output ) :-
swap( Input, J, I, Output, _, _ ).
swap( [E2|Ls], I, 0, [E1|Ls], E1, E2 ):-!.
swap( [E1|Es], 0, J, [E2|Rs], E1, E2 ) :-
N2 is J - 1,
swap( Es, -1, N2, Rs, E1, E2 ),!.
swap( [E|Es], [I|J], [E|Rs], E1, E2 ) :-
N1 is I - 1,
N2 is J - 1,
swap( Es, N1, N2, Rs, E1, E2 ).
But I am only able to use "one" list as the indexes of what that has to be swapped, like [1,2], what I am looking for is being able to use multiple like [[1,2],[2,3]] and so on.
This answer is based on this previous answer by #user27815.
Here comes the lambda + meta-predicate variant!
:- use_module(library(lambda)).
swap2(Ls0, Swaps, Ls) :-
foldl(\[I,J]^S0^S^list_i_j_swapped(S0,I,J,S), Swaps, Ls0,Ls).
Sample query:
?- swap2([3,1,2], [[0,1],[1,2]], Xs).
X = [1,2,3]
; false.
Using list_i_j_swapped/4
list_i_j_swapped(As,I,J,Cs) :-
same_length(As,Cs),
append(BeforeI,[AtI|PastI],As),
append(BeforeI,[AtJ|PastI],Bs),
append(BeforeJ,[AtJ|PastJ],Bs),
append(BeforeJ,[AtI|PastJ],Cs),
length(BeforeI,I),
length(BeforeJ,J).
swap(List,[],List).
swap(List1,Swaps,ListSwapped):-
Swaps =[[Index1,Index2]|T],
list_i_j_swapped(List1,Index1,Index2,List2),
swap(List2,T,ListSwapped).
Q:
?- swap([3,1,2],[[0,1],[1,2]],X).
X = [1, 2, 3] ;
false.
The positions are zero indexed.

How can I remove zero values from list?

How can I remove zero values from the result list after the concatenation of two lists?
This is the code I've made to merge 2 lists but I'm stuck how to approach the removal of zero from the result list.
Code:
merge([], [], _).
merge([H1|T1], [H2|T2], [H2|T]) :-
H1 > H2,
merge([H1|T1], T2, T),
!.
merge([H1|T1], [H2|T2], [H1|T]) :-
H1 =< H2,
merge(T1, [H2|T2], T),
!.
merge([], [H2|T2], T) :-
append([], [H2|T2], T).
merge([H1|T1], [], T) :-
append([], [H1|T1], T).
The following code takes the list with zeroes as first argument and list without as second. It works by peeling of the head of the first list: if it's a zero, the second list doesn't need it. when you hit the empty string, you're done. prolog will now backtrack and build up the second list.
delete([],[]).
delete([0|T], L) :- delete(T, L).
delete([H|T], [H|T2]) :- delete(T, T2).
haven't tested it but I'm pretty sure it should give you
?- delete([1,2,0,3,4,0,5],0,R). R = [1, 2, 3, 4, 5].

Prolog sorting list using sort method

sort([ [30,100], [10,11] ], X).
gets
X = [[10,11],[30,100]]
How can I sort only by the first index of each sublist?
i.e
X = [[10,100], [30, 11]]
Thanks
The simpler way should be perusing the available builtins. Then take the first element from each sublist, sort them, and replace in the original:
sortfirst(L, S) :-
maplist(get_first, L, A),
msort(A, B),
maplist(set_first, L, B, S).
get_first([E|_], E).
set_first([_|R], E, [E|R]).
edit: note that msort is required, to avoid losing duplicates.
test:
?- sortfirst([ [30,100], [10,11] ], X).
X = [[10, 100], [30, 11]].
get/set first are just needed to adjust the arguments from maplist: if we use lambda, we can write a true 'one liner' procedure:
:- [lambda].
sortfirst_lambda(L, S) :-
maplist(\X^Y^(X = [E|_], Y = E), L, A),
msort(A, B),
maplist(\X^Y^Z^(X = [_|R], Y = E, Z = [E|R]), L, B, S).
Simple identities can simplify a little that expressions:
sortfirst_lambda(L, S) :-
maplist(\X^Y^(X = [Y|_]), L, A),
msort(A, B),
maplist(\X^Y^Z^(X = [_|R], Z = [Y|R]), L, B, S).
edit: or still more simplified:
sortfirst_lambda(L, S) :-
maplist(\[Y|_]^Y^true, L, A),
msort(A, B),
maplist(\[_|R]^Y^[Y|R]^true, L, B, S).
Here you can see that, as in the original get/set first, just the unification of arguments is needed.
Thus lambda it's syntactically convenient, but has its cost:
?- randomlists(100000, 3, -30,+30, L),
time(sortfirst(L,A)),
time(sortfirst_lambda(L,B)),
assertion(A=B).
% 400,012 inferences, 0,482 CPU in 0,483 seconds (100% CPU, 830072 Lips)
% 1,700,012 inferences, 1,717 CPU in 1,721 seconds (100% CPU, 990302 Lips)
L = [[-8, -13, 11], [-13, -27, -29], [5, 10, -24], [-8, -7, -6], [3, -24, -9], [-13, -20, -24], [7, 27|...], [-5|...], [...|...]|...],
A = B, B = [[-30, -13, 11], [-30, -27, -29], [-30, 10, -24], [-30, -7, -6], [-30, -24, -9], [-30, -20, -24], [-30, 27|...], [-30|...], [...|...]|...].
here are the service predicates to build sized test data:
randomlist(Length, Low, High, List) :-
findall(E, (between(1, Length, _),
random(Low, High, E)), List).
randomlists(Length1, Length2, Low, High, ListOfLists) :-
findall(E, (between(1, Length1, _),
randomlist(Length2, Low, High, E)), ListOfLists).
#chac(+1 btw): there's no need of lambda to one-line this (in swi at least!):
sortfirst(L, Res) :-
maplist(selectchk, X, L, R),
msort(X, XS),
maplist(selectchk, XS, Res, R).
but lambda versions or your first version are less tricky and more readable I think!
The below is my untested code.. there may be one/two cosmetic errors... The input list is split into two based on the head value on the list and the resulted two lists are recursively processed to finally result the sorted output.
sort(Input,Output):-sort(Input,[],Output).
sort([],SortedOut,SortedOut).
sort([[Index1,Index2]|Tail],SortedBig,Out):-
split(Tail,[Index1,Index2],LessList,BigList),
!,sort(BigList,SortedBig,NewSort),
sort(LessList,[[Index1,Index2]|NewSort],Out).
split([],[_D],[],[]).
split([[Index1,Index2]|Rem],[Index21,Index22],[[Index1,Index1]|L1],L2):-
Index1<Index21,
!,split(Rem,[Index21,Index22],L1,L2).
split([[Index1,Index2]|Rem],[Index21,Index22],L1,[[Index1,Index1]|L2]):-
!,split(Rem,[Index21,Index22],L1,L2).
Try this and let me know...