write a notSortedDescending function in prolog - list

Write Prolog code that defines a predicate notSortedDescending(Numberlist) that is true if and only if the list of numbers Numberlist is NOT sorted in descending order?
Could anyone help me solve this problem? I only know how to write a sorted function in Prolog. Thank you so much!
notSortedDescending([x , y | z ])  :-
                 ( x => y ) -> notSortedDescending([y|z])
This is what I came up with...

Here is how you would write it in Prolog that compiles:
not_sorted_descending(L) :-
\+ sorted_descending(L).
sorted_descending([]).
sorted_descending([_]).
sorted_descending([X,Y|Xs]) :-
X #>= Y,
sorted_descending([Ys|Xs]).
You need to cover the corner case that all elements are equal. If they are, the list is sorted descending so "not sorted descending" has to fail.
On its own sorted_descending/1 as defined will leave a choice point. Because you negate it this doesn't matter.
You can also take a more functional approach and use a left fold on the list like this:
not_sorted_descending([H|T]) :-
\+ foldl(descending, T, H, _).
descending(V, V0, V) :-
V0 #>= V.

Related

Prolog - find all lists that have established length

I am new to prolog, and I think I have an really easy problem to solve, but i cant find sollution anywhere.
So i have a list of lists and I need to find all elements in it with esteblished length.
This is what i came to, but it is not working.
averegelist_([[]],[[]]).
averegelist_([Wo|List], Averege, NewL):-
length(Wo,N), N+1=:=Averege, averegelist_(List, NewL).
averegelist([Word|List1],Av, [Word|List2]):-
length(Word,N), N+1=\=Av, averegelist_(List1, Av, List2).
What i expected is somethig like this:
?- averegelist([['a','b','c'],['f','g'],['h','m']],2, X)).
X = ['f','g'].
X = ['h','m'].
False
Can somebody help me, please?
Edit:
So, I did it! For anyone interested in this topik this is what my code looks like:
split_on_delimiter(L, D, S) :-
split_on_delimiter_(L, D, R),
findall(X, (member(X, R), length(X,Length), Length > 0), S).
split_on_delimiter_([], _, [[]]).
split_on_delimiter_([D|T], D, [[]|T2]) :-
split_on_delimiter_(T, D, T2).
split_on_delimiter_([H|T], D, [[H|T2]|T3]) :-
dif(H, D),
split_on_delimiter_(T, D, [T2|T3]).
my_length([],0).
my_length([_|L],N) :- my_length(L,N1), N is N1 + 1.
my_length_lol([], 0).
my_length_lol([H|L],N) :- my_length(H,Add), my_length_lol(L,N1), N is N1 + Add.
countAver(L,Av):- length(L,ListN), my_length_lol(L,AllN), Av is div(AllN,ListN).
test_condition(X, Con):- length(X, N), N =:= Con.
select_element_on_condition([X|Xs], X, Con) :-
test_condition(X, Con).
select_element_on_condition([_|Xs], X, Con) :-
select_element_on_condition(Xs, X, Con).
findAvWord(L, X):- split_on_delimiter(L,' ', Words), countAver(Words, AvWordLength),
write(AvWordLength), select_element_on_condition(Words, X, AvWordLength).
findAvWord(L, X) L - is a list of simbols, X - is a word of averege Length in this list.
split_on_delimiter(L,D,S) S is - list of lists from L, based on delimiter(' ' in my case)
I think you're making this problem harder than it really is. Here's a simple predicate framework that succeeds for list elements that meet a specific criteria. You should be able to adapt this to your problem.
select_element_on_condition([X|Xs], X) :-
test_condition(X).
select_element_on_condition([_|Xs], X) :-
select_element_on_condition(Xs, X).
In your case, your elements are lists, and the test condition is for the length.
just to show how to solve such problem using modern libraries like apply and yall - where available -
averegelist(Lists, Length, ListsOfLength) :-
include({Length}/[List]>>length(List,Length), Lists, ListsOfLength).

specific sorting in PROLOG

I have to write a predicate insort/2 which reduces any list (with possibly
duplicated elements) to a list in which each distinct element appears only once
and a specific order is used. For example,
? - insort([a,[a,a],[a,b],[b,a],[[a,b]],[d],c],X).
X = [a,c,[a],[d],[a,b],[[a,b]]]
yes
? - insort([[a,[a,b]],[a,[c,b]],[[a,b],a]], X).
X = [[a,[a,b]],[a,[b,c]]]
yes
? - insort([[a,b],[a,[a]],[a,b,c]],X).
X = [[a,b],[a,[a]],[a,b,c]]
yes
The order should first examine the total length of the list and the list with smaller total length is “smaller”. If total length is the
same then the natural order of terms in PROLOG should be adopted. But final solution cannot use SWI-Prolog built-in sort/2 and merge/3 predicates.
My work for now is like that:
rlen([],0).
rlen(X,1).
rlen([Head|Tail],N):-rlen(Head,Q1),rlen(Tail,Q2),N is Q1+Q2.
member(Head, [Head|Tail]).
member(X, [Head|Tail]) :- member(X,Tail).
remove_duplicates([],[]).
remove_duplicates([H | T], List) :-
member(H, T),
remove_duplicates( T, List).
remove_duplicates([H | T], [H|T1]) :-
\+member(H, T),
remove_duplicates( T, T1).
count(_,[],0).
count(X,[X],1).
count(X, [X|Y],N):- count(X,Y,W),N is W + 1.
count(Z,[X|Y],N):- count(Z,Y,N),X\=Z.
elsort([],[]).
elsort([A|B],C):-
elsort(B,D),
(is_list(A)->elsort(A, SA);SA=A),
elsortx(SA,D,C).
elsortx(A,[X|B],[X|C]):-
order(X,A),
!,
elsortx(A,B,C).
elsortx(A,B,[A|B]).
order(X,Y) :- is_list(X), is_list(Y), length(X,A),length(Y,B),A<B.
order(A,A2):-
A #< A2.
But still missing some things, I don't know how use here remove_duplicates,
and why order([[a,b]],[a,b]). throws true, should be false
Thanks for help, I really don't know how handle this

Subtracting or adding lists of lists in prolog?

I am fairly new to prolog and am trying to mess around with lists of lists. I am curious on how to add two lists of lists or subtract them resulting in one list of list. If I have two lists of lists lets say,
SomeList = [[1,2,3,4],[5,6,7,8]]
SomeList2 = [[1,2,3,4],[5,6,7,8]]
How could I add or subtract SomeList and SomeList2 to create a list of lists? Resulting in a sum of say
sumList([[2,4,6,8],[10,12,14,16]])
or vice-versa for subtraction? Any help would be appreciated not looking for code but for insight !
The easiest approach is with maplist:
add(X, Y, Z) :- Z is X + Y.
op_lists(L1, L2, R) :-
maplist(maplist(add), L1, L2, R).
Which gives:
| ?- op_lists([[1,2,3,4],[5,6,7,8]], [[1,2,3,4],[5,6,7,8]], R).
R = [[2,4,6,8],[10,12,14,16]]
yes
| ?-
In the expression:
maplist(maplist(add), L1, L2, R).
maplist(G, L1, L2, R) calls G on each element of L1 and L2, resulting in each element of R. Since each element of L1 and L2 is a list, then G in this case is maplist(add) which calls add on each element of the sublists.
You can obviously modify add(X, Y, Z) to be whatever operation you wish on each pair of elements. You can also make the addition more "relational" by using CLP(FD):
add(X, Y, Z) :- Z #= X + Y.
Then you also get, for example:
| ?- op_lists([[1,2,3,4],[5,6,7,8]], L, [[3,6,9,12],[10,12,14,16]]).
L = [[2,4,6,8],[5,6,7,8]]
yes
| ?-
If you wanted to do this without maplist, you could still use add/3 and use a two-layer approach:
op_lists([], [], []).
op_lists([LX|LXs], [LY|LYs], [LR|LRs]) :-
op_elements(LX, LY, LR),
op_lists(LXs, LYs, LRs).
op_elements([], [], []).
op_elements([X|Xs], [Y|Ys], [R|Rs]) :-
add(X, Y, R),
op_elements(Xs, Ys, Rs).
You can see the simple list processing pattern here, which the use of maplist takes care of for you.
Besides the solutions presented by #lurker (+1), I would also add the possibility to use DCGs, since you are working on lists. For the available operations I suggest to define a slightly more general predicate opfd/4 instead of add/3. Here are exemplary rules for addition and subtraction as asked in your question, you can use these as templates to add other two-place arithmetic operations:
opfd(+,X,Y,Z) :-
Z #= X+Y.
opfd(-,X,Y,Z) :-
Z #= X-Y.
As the desired operation is an argument, you only need one DCG-rule to cover all operations (marked as (1) at the corresponding goal). This way, of course, you have to specify the desired operation as an argument in your relation and pass it on to the DCGs. The structure of these DCGs is very similar to the last solution presented by #lurker, except that the resulting list does not appear as an argument since that is what the DCGs describe. For easier comparison I will stick with the names op_lists//3 and op_elements//3, the calling predicate shall be called lists_op_results/4:
lists_op_results(L1,L2,Op,Rs) :-
phrase(op_lists(Op,L1,L2),Rs).
op_lists(_Op,[],[]) -->
[].
op_lists(Op,[X|Xs],[Y|Ys]) -->
{phrase(op_elements(Op,X,Y),Rs)},
[Rs],
op_lists(Op,Xs,Ys).
op_elements(_Op,[],[]) -->
[].
op_elements(Op,[X|Xs],[Y|Ys]) -->
{opfd(Op,X,Y,R)}, % <-(1)
[R],
op_elements(Op,Xs,Ys).
Example queries:
?- lists_op_results([[1,2,3,4],[5,6,7,8]], [[1,2,3,4],[5,6,7,8]], +, R).
R = [[2,4,6,8],[10,12,14,16]]
?- lists_op_results([[1,2,3,4],[5,6,7,8]], [[1,2,3,4],[5,6,7,8]], -, R).
R = [[0,0,0,0],[0,0,0,0]]
#lurker's example:
?- lists_op_results([[1,2,3,4],[5,6,7,8]], L, +, [[3,6,9,12],[10,12,14,16]]).
L = [[2,4,6,8],[5,6,7,8]]
You can also ask if there is an operation that fits the given lists:
?- lists_op_results([[1,2,3,4],[5,6,7,8]], L, Op, [[3,6,9,12],[10,12,14,16]]).
L = [[2,4,6,8],[5,6,7,8]],
Op = + ? ;
L = [[-2,-4,-6,-8],[-5,-6,-7,-8]],
Op = -
On a sidenote: Since the operation is the first argument of opfd/4 you can also use it with maplist as suggested in #lurker's first solution. You just have to pass it lacking the last three arguments:
?- maplist(maplist(opfd(Op)),[[1,2,3,4],[5,6,7,8]], L, [[3,6,9,12],[10,12,14,16]]).
L = [[2,4,6,8],[5,6,7,8]],
Op = + ? ;
L = [[-2,-4,-6,-8],[-5,-6,-7,-8]],
Op = -

Check if list is ordered

I'm trying to compare the elements of a list of integer to see if they are ordered (or not). I'm using Amzi!
I gave a few attempts, but nothing works... :(
ordered([X]).
ordered([N|[N1|L]]) :- N <= N1, ordered([N1|L]).
ordered_([X]).
ordered_([Head,Head1|Tail]) :- Head <= Head1, ordered_([Head1|Tail]).
Both return no if this list is entered:
ordered([1,2,3,4]).
ordered_([1,2,3,4]).
I understand that I need to compare the head with the head of the tail.
Doesn't seem like it should be any more complex than
ordered( [] ) .
ordered( [_] ) .
ordered( [X,Y|Z] ) :- X =< Y , ordered( [Y|Z] ) .
Arithmetic comparison predicates are covered here: http://www.amzi.com/manuals/amzi/pro/ref_math.htm#MathematicalComparisons
Use #=</2 or compare/3 to check the ordering of things in the standard order of terms: http://www.amzi.com/manuals/amzi/pro/ref_manipulating_terms.htm#StandardOrder
a compact alternative:
ordered(L) :- \+ ( append(_,[A,B|_], L), A > B ).
More efficient alternative to most upvoted solution, comparing three instead of appending the bigger element back to the list
is_sorted([]).
is_sorted([X, Y, Z|T]) :- X =< Y, Y =< Z, is_sorted(T).
is_sorted([X, Y|T]) :- X =< Y, is_sorted(T).

How to implement a fill method in prolog

I'm rather new to prolog and I am trying to implement a method called fill
which has the structure
fill(4,1,X).
X = [1,1,1,1]
However I not sure how to implement this because I know prolog do not allow indexed list. So how am I suppose to return an array.
fill(N, E, Xs) :-
length(Xs, N), % Xs is a list of length N
maplist(=(E), Xs). % all elements in Xs are equal to E
%fill(+N,+X,-L) element X is replicated N times
fill(0,_,[]).
fill(N,X,[X|Xs]) :- N > 0, N1 is N-1, fill(N1,X,Xs).
findall/3 it's the swissknife for list building:
fill(N, E, Xs) :- findall(E, between(1, N, _), Xs).