Tail of List is always empty - prolog

I have a list of which i gotta extract Size items and that makes up the Group.
The remaining items in the list are the Persons_Rest.
My code is working perfectly fine so far, only that I have a empty tail in my Group, so the first variable.
I know it is, because the parameters of my accumulator method is [Head|Tail]. But I cant find out how to avoid the empty tail.
make_one_group(Group, All_Persons, Persons_rest, Size):-
make_one_group_acc(Group, All_Persons, All_Persons, Persons_rest, 0, Size).
make_one_group_acc(Group, All_Persons, Persons_rest, Persons_rest, Size, Size).
make_one_group_acc([H_group|T_group], All_Persons, Persons_rest_acc, Persons_rest, Counter, Size) :-
ReplaceCounter is Counter+1,
make_one_group_acc(T_group, All_Persons, New_Persons_rest, Persons_rest, ReplaceCounter, Size),
my_select(H_group, Persons_rest_acc, New_Persons_rest).
my_select(Elem, [Elem|T], T).
my_select(Elem, [H|T], [H|T2]) :-
my_select(Elem, T, T2).

Related

Remove duplicates in a list without using built-in predicates and maintaining order

I am new to prolog and want to remove duplicates and maintain order. My logic is taking a list, dividing it to a Head|Tail, taking an accumulator and solving recursively as:
is head in accumulator?
yes- do nothing
no - add head to accumulator
This is what I have gotten so far:
is_member(X,[X|_]).
is_member(X,[_|T]) :- is_member(X,T).
remove_duplicates(List, Set) :- help_remove_duplicate(List, [], Set).
help_remove_duplicate([], Acc, Acc).
help_remove_duplicate([H|T], Acc, Set) :-
is_member(H, A),
help_remove_duplicate(T, Acc, Set).
help_remove_duplicate([H|T], Acc, Set) :-
help_remove_duplicate(T, [H|Acc], Set).
The above code works for removing duplicates but messes up the order.
[1,2,3,4,4,4,5] returns [5,4,3,2,1].
Any ideas on how to fix this?

Find first sublist that has all numbers from 1 to K

I need to find the first sublist having all numbers from 1 to K and return it and its length.
Sorry in advance for the bad editing
So I check if 1 to K is in sublist if not then I delete the element (Hd) from
NumList ,append it to our result(SubList) and recursively call the function
with the tail as our new List to check.
findFirstSubListHavingAllColors( NumList, [Hd|Tl] ,SubList, X):-
( oneToKinSub(SubList,NumList)
-> length(SubList,X)
; delete(NumList,Hd,NumList1),
append(SubList,[Hd],SubList1),
findFirstSubListHavingAllColors(NumList1,Tl,SubList1,_)
).
oneToKinSub(_,[]).
oneToKinSub(SubString,[Hd|Tl]) :-
member(Hd,SubString),
oneToKinSub(SubString,Tl).
For instance if
NumList =[1,2,3]
[Hd|Tl] =[1,3,1,3,1,3,3,2,2,1]
the expected result should be SubList=[1,3,1,3,1,3,3,2] and X= 8
You may use append/3 and subtract/3 to obtain the first sublist that contains all items:
findFirstSubListHavingAllColors( NumList, List ,SubList, Len):-
once((
append(SubList, _, List), % get SubList
subtract(NumList, SubList, []), % test whether NumList is contained in SubList
length(SubList, Len)
)).
once/1 here is to avoid getting other (wrong) solutions on backtracking.
Here is another solution using aggegate_all/3
firstSubList(NumList, In, Out) :-
aggregate_all(max(E),(member(X, NumList), once(nth1(E, In, X))), Len),
length(Out, Len),
append(Out, _, In).
Once/1 is used because numbers may appears many times in the list !

Selection sort using max

I am trying to implement a custom version of selection sort, by selecting the maximum of the unsorted part and placing it at the end of the output (sorted) list.
I have a problem with the list recursive build. How can I start building the output list from the right?
sel_sort2([], []).
sel_sort2(L, R) :-
max_list(L, M),
delete1(M, L, L1),
append(R, [M], R),
sel_sort2(L1, R).
You don't need to use append (which as pointed in the first comment is fishy). Instead you can write the second clause like:
sel_sort2(L, [E|T]) :-
min(L, E),
del(L, E, L1),
sel_sort2(L1, T).
Where min takes the minimum element from the input list, and this element is on the first position in the result list, L1 is all elements from L without the first occurrence of a given element.

Prolog minimum value in a list

I'm working on defining a predicate min_in_list/2 that would find the smallest value on a list. If there is less than 2 elements in the list the program should output "Error: There are not enough elements in the list" and if an element on the list is not a digit Eg. [2,a,3]. The program should output "Error: The element is not a number". I created a predicate that would find the smallest value and checking if the list has less than two values but I'm having problem on checking if an element of a list is not a digit and outputting the error message
My code:
min_in_list([Min],_):- write('ERROR: List has fewer than two elements.').
min_in_list([],_):- write('ERROR: List has fewer than two elements.').
min_in_list([Min,_],Min).
min_in_list([H,K|T],M) :-
H =< K,
min_in_list([H|T],M).
min_in_list([H,K|T],M) :-
H > K,
min_in_list([K|T],M).
The test you're looking for is number/1, which tells you whether a value is a number or not. My final code looks like this:
min_in_list([], _) :- domain_error(not_empty_list, []).
min_in_list([X], _) :- domain_error(not_single_item_list, [X]).
min_in_list([X,Y|Rest], Min) :- min_in_list(X, [Y|Rest], Min).
min_in_list(Min, [], Min) :- !.
min_in_list(Min, [X|Rest], FinalMin) :-
( number(X) ->
(NewMin is min(Min, X),
min_in_list(NewMin, Rest, FinalMin))
;
type_error(number, X)
).
I'm still not entirely sure how to format a condition like this, but splitting it into separate predicates seems like an awful waste. Hopefully someone will come along and tell me how to format this so that it is attractive.
If you are using SWI-Prolog, you can simplify things using must_be/2:
min_in_list(Min, [], Min).
min_in_list(Min, [X|Rest], FinalMin) :-
must_be(number, X),
NewMin is min(Min, X),
min_in_list(NewMin, Rest, FinalMin).
The simplest solution can be:
list(Min, [Min]).
list(Min, [H|T]) :- list(PMin, T), Min is min(H, PMin).
However it must be note, that it will be stack overhead on big arrays.

Applying Effects on A State List

I want to apply a list of effects in a current state in other words, have a list of effects generated by an action if the current state has a condition that corresponds to the denial of a effect that condition will be removed.
If i have the current state:
[clear(b),on(b,a),on(a,mesa),clear(d),on(d,c),on(c,desk)]
And the list of effects :
[-clear(d), -on(d.c), on(c,d)]
The result would be :
[clear(b),on(b,a),on(a,mesa), on(c,d), on(c,desk)]
This is what i got right now, any help would be appreciated!
applyEffects(currentState,Effects,result)
insert(Element, List,result)
remove(Element,List, result)
applyEffects([],L,L).
applyEffects(L,[],L).
applyEffects([X|XTail], [-X|YTail], A) :-
insert(X, A, B),
applyEffects([X|XTail],YTail, B).
insert(E, L1, [E|L1]).
remove(X, [X|L1], L1).
remove(X, [Y|L1], A):- remove(X,L1,[L1|Y]).
Your insert and remove should both be select (which is often built-in).
You might want to distinguish, if you have a "negative" argument or not:
applyEffects(L,[],L).
applyEffects(L,[-X|R],A):-
!,
applyEffects(L,R,Y),
select(X,Y,A).
applyEffects(L,[X|R],[X|Y]):-
applyEffects(L,R,Y).
The cut used in the second clause is a red cut, to make it green, add a \+ X = - _ line to the third clause.
if you want to allow non-existing negatives, change the second clause to this:
applyEffects(L,[-X|R],A):-
!,
applyEffects(L,R,Y),
(select(X,Y,A),!;
Y = A).
Now applyEffects([],[-on(something)],X) doesn't fail.

Resources