Related
I am trying to figure out how to do this little thing. I have 2 lists for example [1,1,2,3,4] and [2,1,4,3,1], I need to confirm if all elements from list 1 are included in list 2, soo if i give the above lists as input this should be true, but if its like this [1,1,2,3,4] and [2,1,4,3,1,1] (three 1's) it should give false, this has to be done without using sort function.
I assume you know how to write a list as head and tail ([H|L]).
So you could use the predicate member/2 to ask for every element from the first list to be in the second list as well, but this would not solve the issue of duplicates. Using the predicate length/2 will not help in this case. So you need something that retracts one matching element from a list. You can either write your own find-and-remove-predicate or use the predicate append/3 to do so. append/3 is thought to append 2 lists to form a third one, but it can also be used to divide one list into two. If you state that your element as the head element of the second divided list you basically get a 'remove element' functionality. Once you've got the 2 divided lists, combine them into a new list and call the predicate again, but this time without the head element from list one and with the reappended-list. So in each step you remove one element from each list until you finally hit two empty lists (permut([],[]).). If something other than this two cases should appear, then the two lists are not permuations of each other and the predicate fails.
Since there is no use in backtracking other positions I inserted a cut (!) after successfully finding an element in the second list. The predicate works without the cut as well.
permut([],[]).
permut([H|T], Compare):-
append(C1, [H|C2], Compare),
!,
append(C1, C2, Cnext),
permut(T, Cnext).
gives the output
?- permut([1,2,3,4,5],[5,4,3,2,1]).
true.
?- permut([1,2,3,4,5],[5,4,3,2,1,1]).
false.
?- permut([1,2,3,4,5,6],[5,4,3,2,1]).
false.
I'm new to Prolog. Consider the following example:
MainList = [["A","a","0"],["A","b","0"],["B","a","0"],["B","b","0"],["A","a","1"],["B","b","1"],["C","c","1"],["C","a","0"]]
SubList = ["A","b","-']
The format of MainList: in the first index it should be the big letter, second index should be small letter and third index should be number. MainList can contain other formats (and lengths) but I choose this format because it is easier to explain. I just want to explain that there index of each sublists are divided into categories - first element of each list belongs to category1, second element to category2 and so on. The "-" symbol means we does know about the bond of that element with the other elements.
The relation I would like to create should go through the MainList and remove all of the sublists that does not follow SubList. For the example above, it should return:
Output = [["A","b","0"],["B","a","0"],["C","c","1"],["C","a","0"]]
Explanation: "A" is working together with "b" so every sublists that contains one of those elements, should be checked. if they both exists then it's ok (without duplicates). Otherwise if only one of them exists, it is not ok and we should not insert it into the Output list.
Another example (MainList is a bit different than the one before):
MainList = [["A","a","0"],["A","b","0"],["B","a","0"],["B","b","0"],["A","b","1"],["B","b","1"],["C","c","1"],["C","a","0"]]
SubList = ["C","a","0"]
Output = [["A","b","1"],["B","b","1"],["C","a","0"]]
I do understand the algorithm - we should go through each sublist of the MainList and check if the connection of the input-sublist is working, if so, we will insert it into the Output list. The problem is, I don't understand how to implement it right. What if the sublist contains more than 2 connections (as was shown in the second example)? How should I treat differently to the sublist?
EDIT: I'll try to explain a bit more. The place of each element is important. Each place represents a different category. For example, the first place might represent the big letters, the second place represents the small letters and the third place represents numbers (there could be more categories).
We get a sublist which represents a bond between two or more elements. For example we have a bond between "A" and "b": ["A","b","-"]. We should iterate through the sublists of MainList and check if each one of those sublists contains one of those elements ("A" and "b"). If it does, we should check if the bond is correct. For example if we have a sublist that has A (in the first index of course), then we should go to the second index and check if "b" is there. if it is not there, we should not insert it into the Output list, Otherwise we will insert. For example we have a bond ["A","b","-"] and we got into a sublists of MainList which looks as following: ["A","a","0"] or ["B","b","2"]. We will not inert those lists into Output. But if we got to sublists like: ["A","b","1"] and ["A","b","2"] and ["B","a","1"] we will insert those lists into Output.
I wrote a code that satisfies the output conditions for the examples you have given, but did not try other cases or consider the efficiency of the code, so you can maybe improve upon it. Here is the code :
subList(List,SubL,Out):-
(member("-",SubL),
select("-",SubL,SubRem)
;
\+ member("-",SubL),
SubRem = SubL),
findall(L,((member(L,List),checkEq(SubRem,L));
(member(L,List),checkNeq(SubRem,L))),Out).
checkEq([],_).
checkEq([S|Rest],[E|List]):-
S == E,
checkEq(Rest,List).
checkNeq([],_).
checkNeq([S|Rest],List) :-
\+ member(S,List),
checkNeq(Rest,List).
Explanation: What I did is that, first I removed the "-" character from the subarray(if it exists) in order to make the computations easier. Then, I either check the condition that each element in the SubList is in order with the elements of the selected sublist of the MainList. If this fails, I then check if none of the elements of SubList is contained in the selected sublist. If both checks fail, I move to the next sublist. Using findall/3 predicate, I find all combinations that satisfy either of these conditions and group them in the list Out
EDIT: Add the additional clause for the checkEq predicate :
checkEq([S|Rest],[E|List]):-
S \= E,
member(S,List),
checkEq([S|Rest],List).
So the final version is :
checkEq([],_).
checkEq([S|Rest],[E|List]):-
S == E,
checkEq(Rest,List).
checkEq([S|Rest],[E|List]):-
S \= E,
member(S,List),
checkEq([S|Rest],List).
I am trying to write a predicate that succeeds if and only if the numbers in the list are in non-decreasing order. I am having a hard time trying to figure this out. I know that if each element is less than or equal to the previous one then it should return false but I am lost on how to do it.
ordered(L) :-
Recursion should usually be your first thought for approaching any problem in Prolog. This means:
Defining a base case, where you can easily determine that the predicate is true or false
In other cases, splitting the problem into parts - one part you can resolve immediately, another you can resolve recursively. These parts of the problem generally correspond to portions of the list.
In the simplest cases, the recursive logic is simply to apply some test to the first element of the list; if it passes, recursively apply the predicate to the remainder of the list.
In your case I think it is a bit more complex, as there is no meaningful way you can test an individual element for orderedness (and maybe that gives you a hint what the base case is ...).
ordered(L) :- ordered2(L).
% empty list is ordered
ordered2([]) :- true.
% list with one element is ordered
ordered2([_]) :- true.
% list is ordered if two first elements are ordered
% and the rest of list is ordered
ordered2([A,B|T]) :- A=<B, ordered2([B|T]).
Given a list (A) I want to be able to create a new list (B) that contains only the elements of A that are the smallest or the biggest compared to their next and previous element. My problem is that I don't know how to do the comparisons of each element with its previous one.
(This question may be silly but I'm new to prolog and any help would be appreciated.)
You could start with something like that:
compareElem([]).
compareElem([H,H1,H2|B]):-compareElem(B),
compare(?Order, H1,H2),
compare(?Order, H1, H).
where ?Order is the order of comparison (like '<' or '>'). See compare/3.
Some queries:
?- compareElem([1,2,3,4,5,6]).
true.
?- compareElem([1,2,3,4,5,3]).
false.
of course to apply this example you must ensure that the list has 3n elements, this is just a basic example. Together with this comparison you can generate the other list
I find myself narrowing a (very simple) problem more and more.
Let's say I have this operation: listsplit([H1,H2,H3|T], H1,H2,H3, T).
Which gives me the first three elements of a list. I want a program, cells, to travel an input list and make (at least that ONE operation!!) to every element of the list.
So I have something like:
cells(Input, Result):-
cellsBody(Input, [], Result).
cellsBody([],Result,Result).
cellsBody([Head|Input], Acc, [Headd|Result]):-
listsplit(Input,H1,H2,H3,_),
cellsBody(Input, [OutputBody|Acc], Result).
I have that code because I have used many I've seen as examples that go like that to travel a list. They separate head from body and go on. I fail to see how this is done in prolog. I tried changing variable names, so that they would match (as I would do in other languages), and I've tried to make the problem as simple as possible.
So, how do I travel a list AND make operations to every element (that I choose to, starting with the first one, the head).
Edit: Examples of what I want to archieve:
I get an input list like oxo, oxxxo, oxoxo, so on. I then apply a rule to the first three elements, then the next three, and so on, and while I do that I add the result of the rule to another list that I return (which is why I am trying to use the accumulator).
You've almost got it. Keeping your predicate cells/2 as is, think about the special cases first: The lists [], [_], [_,_] haven't got three elements, so whatever operation you have in mind for those three elements, there's nothing to do in these cases. Otherwise you have a recursive rule to do what you intend to.
Looking at listsplit/5: you can do that directly in the head of the recursive rule, no need for an extra predicate. Then you have one or more goals for your intended operation. For the sake of an example let's say packaging the 3 head elements as a triplet. And of course the relation must hold for the tail T of the list too. Then your code might look something like that:
cellsBody([],Result,Result).
cellsBody([_],Result,Result).
cellsBody([_,_],Result,Result).
cellsBody([H1,H2,H3|T], Acc, Result):- % the first 3 elements
Triplet=(H1,H2,H3), % at least ONE operation with them
cellsBody(T, [Triplet|Acc], Result).
Example queries:
?- cells([],Result).
Result = []
?- cells([1],Result).
Result = []
?- cells([1,2],Result).
Result = []
?- cells([1,2,3],Result).
Result = [(1,2,3)]
?- cells([1,2,3,4,5,6,7],Result).
Result = [(4,5,6),(1,2,3)]
Of course, if the intended operation is as simple as in the above example, you don't need an extra goal for it: You can do that directly in the recursive goal:
cellsBody([H1,H2,H3|T], Acc, Result):-
cellsBody(T, [(H1,H2,H3)|Acc], Result).