Reputation: 271
i want remove elements from a list but if i do this:
deletelist([3,1,2,3,4], [3], [3,1,2,4])
how remove only a 3 and not get this answer:
deletelist([3,1,2,3,4], [3], [1,2,4])
Thanks!
Upvotes: 1
Views: 691
Reputation: 11267
If you want to get just unique values in list - use function list_to_set/2:
list_to_set([3,1,2,3,4],X)
gives X = [3, 1, 2, 4].
EDIT:
So gnu prolog
doesn't have built-in predicate list_to_set
. You have to write it yourself.
For this you must define set concept. What is set of list
? Set should have these attributes:
Based on these assumptions you can write set_from_list
predicate like this:
elem_unique(Elem, List) :-
delete(List, Elem, ListWithoutElem),
length(List, OrgLength),
length(ListWithoutElem, DelLength),
DelLength + 1 =:= OrgLength.
nth_elem_isUnique(N, List) :-
nth1(N, List, Elem),
elem_unique(Elem, List).
nth_elemOfList1_isMemberOfList2(N, List1, List2) :-
nth1(N, List1, Elem),
member(Elem, List2).
elements_from_nth_areUnique(N, List) :-
(length(List, Len),
N > Len) %stoping condition for recursion
;
(nth_elem_isUnique(N, List),
M is N + 1,
elements_from_nth_areUnique(M, List) %recursion part
).
listIsUnique(List) :-
elements_from_nth_areUnique(1, List).
elements_from_nth_inList1_areMembersOfList2(N, List1, List2) :-
(length(List1, Len),
N > Len) %stoping condition for recursion
;
(nth_elemOfList1_isMemberOfList2(N, List1, List2),
M is N + 1,
elements_from_nth_inList1_areMembersOfList2(M, List1, List2) %recursion part
).
list2containsList1(List1, List2) :-
elements_from_nth_inList1_areMembersOfList2(1, List1, List2).
set_from_list(Set, List) :-
length(Set, LenSet),
length(List, LenList),
LenSet =< LenList,
list2containsList1(List, Set),
list2containsList1(Set, List),
listIsUnique(Set),
!.
So after calling set_from_list(Set, [3,1,2,3,4])
you will get Set = [3,1,2,4]
.
Upvotes: 1
Reputation: 60014
select/3 it's an useful builtin, frequently used to generate and test
, and you can use to delete an element:
?- select(3,[3,1,2,3,4],L).
L = [1, 2, 3, 4] ;
L = [3, 1, 2, 4] ;
false.
each call removes a match, then you can control the desired behaviour
edit
to delete all elements from the second list:
deletelist(L, [], L).
deletelist(With, [D|Ds], Without) :-
select(D, With, WithoutD),
deletelist(WithoutD, Ds, Without).
Note that this will fail if any of elements to be deleted will not be found in list. To avoid this, apply a 'if .. then .. else ..'
deletelist(L, [], L).
deletelist(With, [D|Ds], Without) :-
( select(D, With, WithoutD)
-> deletelist(WithoutD, Ds, Without)
; deletelist(With, Ds, Without)
).
Now deletelist/3 will not enumerate all possible deletions. It commits to the first found. To resume the initial behaviour, that give on bactracking all different deletions, a less efficient procedure is required:
deletelist(L, [], L).
deletelist(With, [D|Ds], Without) :-
select(D, With, WithoutD),
deletelist(WithoutD, Ds, Without).
deletelist(With, [D|Ds], Without) :-
\+ select(D, With, _),
deletelist(With, Ds, Without).
Upvotes: 2