Essentially what I want to do is this: Given a list comprised of tuples [(x,[y])] and another list of strings [a], I want to create a new list of all the [y]'s where x == a if that makes sense, so if I have [('a', ['z', 'k', 'x']), ('b', ['z']), ('c', ['y', 'j'])] and ['a', 'c'], the resulting list when both lists are passed through the function would be [['z', 'k', 'x'], ['y', 'j']].
The solution I came up with is kind of ridiculous and over complicated, (as well as non-functional) but just so you can see what kind of path I've been thinking about I'll post it below.
foo ys xs acc = map (\x -> (map (\(a,y) -> if x == a then y:acc else []) ys)) xs
This prints what I want but also prints tons of extra brackets that makes the output super confusing, no doubt because I've bastardized the map function. Any suggestions?
Given
l1 = [('a', ['z', 'k', 'x']), ('b', ['z']), ('c', ['y', 'j'])]
l2 = ['a', 'c']
a quick and intuitive solution is
filter (\(c,_) -> c `elem` l2) l1
which filters l1 retaining only those pairs whose first element is an element of l2.
The filtering predicate (\(c,_) -> c `elem` l2) can also be written as ((`elem` l2) . fst).
As regards performance, if the fact that l2 is sorted and l1 is sorted with respect to the fsts is just a matter of concidence or oversimplification of the example, we can observe that filtering is a linear operation, because you have to traverse all the elements of l1 to decide if each one has to be retained or filtered out. But maybe the look up operated by `elem` l2 can be improved by making l2 a Set, which is done by simply changing `elem` l2 to `elem` Data.Set.fromList l2.
If, instead, the lists are truly sorted as in the example, then other approaches are possible. Just as an example, if l1 was the same as above, but l2 was ['d', {-whatever-}], then you'd know that the output is empty.
Assuming the two lists are sorted, like in your example, then you can iterate through both lists simultaneously, using pattern-matching and guards:
foo ((x,y):xs) (z:zs) | x == z =
foo ((x,_):xs) (z:zs) | x < z =
foo ((x,y):xs) (z:zs) | x > z =
foo [] _ =
foo _ [] =
I have intentionally blanked everything after the = sign, because I believe you'll learn more if you fill it yourself than if I dump a solution. Although I did leave a small hint by including y where it's needed, and _ instead where it's not needed.
Testing:
ghci> foo [('a', ['z', 'k', 'x']), ('b', ['z']), ('c', ['y', 'j'])] ['a', 'c']
["zkx","yj"]
Related
I have this program that makes multiple replacements in a list given by
another list with pairs in the format (Index, Elem).
Example:
replace_multiple([A, B, C, D, E], [(2, b), (1, a), (3, c), (4, d)]).
###
should result:
####
Lst = [a, b, c, d, E],
false
####
However this is my output:
A = a,
B = b,
C = c,
D = d
false
####
What am i doing wrong?
What am i doing wrong?
Here are a few things:
You may be unsure about the fact that the list you want to replace contains elements starting with uppercase letters, i.e. logical variables.
In replace_multiple/2, the new element is described as Elem in the head, but as Letter in the body.
In replace_multiple/2, the call to replace/4 has Lst on first and second position. The meaning of a logical variable like Lst is the same as the name of a shared global variable, which, however, cannot be modified unless you replace more logical variables in that logical variable with other stuff. So you have the same structure as "input" and "output". This is probably not what you want.
Same for replace_multiple/2 per se, which should take Lst and build ("return") a modified LstMod given as third argument.
There is fat syntax error at the end of replace/4.
It is better to use [x,y] or x-y than (x,y) as a notation for a pair.
Currently I am trying to generate all the possible pairings of elements (a, b), where a is from set A and b is from set B in prolog. For example given:
A = {1 ,2, 3}
B = {a, b, c}
One possible set of pairings would be {(1,a), (2,b), (3,c)}
I want to find all unique sets of pairings for a and b. I believe that the number of possible pairings should be n!.
Here is my attempt. (In my case set A is a list of Employer names and set B is a list of Student names).
generateMatching(Matching, [], [], Matching).
generateMatching(Matches, Employers(A), Students(B), Result) :- member(S, Students), member(E, Employers),
delete(Students, S, Students1), delete(Employers, E, Employers1),
generateMatching([(E, S)|Matches], Employers1, Students1, Result).
and I call it like
generateMatching([], Employers, Students, Matching)
Essentially on each call I am picking some member of the set of Students (S) and some member of the set of Employers (E) and then adding them to the current set of matches (Pairings). I then deleting them from the sets from which they were picked so that they cannot be picked again. I keep doing this until I have 2 empty lists and I know I have found a possible set of pairings.
The problem I is that the solution I have will consider {(1,a), (2,b), (3,c)} and {(1,a), (3,c), (2,b)} to be different pairings, and as a result computation is very slow.
How can I improve this?
EDIT: What I actually want to get after the query is this. To be more clear, a solution is a set of pairing where each element from A is paired with exactly 1 from B and vice-versa
Matching = [(1,a), (2, b), (3, c)] ;
Matching = [(1,a), (2, c), (3, b)] ;
Matching = [(1,b), (2, c), (3, a)] ;
Matching = [(1,b), (2, a), (3, c)] ;
Matching = [(1,c), (2, b), (3, a)] ;
Matching = [(1,c), (2, a), (3, b)] ;
False.
Assuming the de facto standard select/3 predicate is available:
pairs([], [], []).
pairs([E1| R1], L2, [E1-E2| R]) :-
select(E2, L2, R2),
pairs(R1, R2, R).
Sample call:
| ?- pairs([1,2,3],[a,b,c],L).
L = [1-a,2-b,3-c] ? ;
L = [1-a,2-c,3-b] ? ;
L = [1-b,2-a,3-c] ? ;
L = [1-b,2-c,3-a] ? ;
L = [1-c,2-a,3-b] ? ;
L = [1-c,2-b,3-a] ? ;
no
Also, as a general style guideline rule, prefer Key-Value as a pair representation.
I have completed a haskell code to compute the delaunay triangulation of a given point set. However, now i am stuck as to how and what method needs to be completed in prolog
Haskell:
-- The type for a single point.
type Point a = (a,a)
-- The type for a pair of points.
type Pair a = (Point a, Point a)
-- The type for a triple of points.
type Triple a = (Point a, Point a, Point a)
-- Predicate for a triple of 3 points is in CCW order or not
isCCW :: Real a => Triple a -> Bool
isCCW ((x1, y1), (x2, y2), (x3, y3)) = (x2-x1)*(y3-y1)-(x3-x1)*(y2-y1) > 0
-- Convert a triple to a CCW triple
toCCW :: Real a => Triple a -> Triple a
toCCW (p1, p2, p3) = if (isCCW ((( p1, p2, p3 )))) then (p1, p2, p3)
else (p1, p3, p2)
-- Generate all pairs of points from a list of points.
-- Each pair should appear exactly once in the result.
pairsFromPoints :: Real a => [Point a] -> [Pair a]
pairsFromPoints [] = []
pairsFromPoints (x:xs) = map makePair xs ++ (pairsFromPoints xs)
where makePair y = (x,y)
-- Generate all unique CCW triples of points from a list of points
-- Each triple should appear exactly once in the result and be
-- CCW ordered.
triplesFromPoints :: Real a => [Point a] -> [Triple a]
triplesFromPoints [] = []
triplesFromPoints (x:xs) = map makeTriple (pairsFromPoints xs) ++ (triplesFromPoints xs)
where makeTriple (y,z) = toCCW(x,y,z)
And this is the Prolog code that I'm stuck on.
Prolog:
% concatenate(L1, L1, T) is true if and only if T is equal to the concatenation
% of lists L1 and L2.
%
concatenate(L1, L2, T).
% singletons(P, Q) is true if and only if Q is equivalent to the list obtained
% from P if each item in P is wrapped in "[" and "]" to create a singleton list.
%
singletons(P, Q).
% prefix_all(I, P, Q) is true if and only if P is a list of lists and Q is the
% list obtained by prepending I to each element in P.
%
prefix_all(I, P, Q).
% pairs_all(I, P, Q) is true if and only if Q is the list obtained by pairing I
% with each item in P.
%
pairs_all(I, P, Q).
% Predicate to test if three points are in counter-clockwise orientation.
%
is_ccw([[X1,Y1],[X2,Y2],[X3,Y3]]) :- (X2-X1)*(Y3-Y1)-(X3-X1)*(Y2-Y1) > 0.
% ccw(T, U) is true if and only if T and U are triples containing the same
% points and U is in counter-clockwise orientation.
%
ccw(T, U).
% ccw_triples(P, Q) is true if and only if Q is the list containing all the
% triples of points in the list P except arranged in ccw orientation.
%
ccw_triples(P, Q).
% pairs_of_points([H|T], Q) is true if and only if Q is a list containing all of
% the distinct pairs that can be made from the points in the list of points
% [H|T].
%
pairs_of_points([H|T], Q).
% triples_of_points([H|T], Q) is true if and only if Q is a list containing all
% of the distinct triples that can be made from the points in the list of points
% [H|T].
%
triples_of_points([H|T], X).
% is_delaunay_triangle(T, P) is true if and only if no point of the point set P
% is in the circle defined by the triple T (which here you may assume is in CCW
% orientation). This predicate is undefined if P is empty.
%
is_delaunay_triangle(T, P).
% delaunay_triangles(T, P, X) is true if and only if X is the subset of
% triangles from T that are Delaunay triangles for the point set P.
%
% HINT: Define this recursively on the list of triangles T.
%
delaunay_triangles(T, P, X).
% delaunay_triangulation(P, X) is true if and only if X is the list of Delaunay
% triangles for the point list P.
% HINT: Create temporary variables to describe all triples from P as well as all
% CCW triples from P. Use the predicates you've already defined above!
%
delaunay_triangulation(P, X).
I am not exactly sure what exactly the first four methods exactly mean, if someone could give me that as a start i would be content I'm not asking you to do my assignment either but any help would be greatly appreciated!
concatenate(L1, L1, T) is true if and only if T is equal to the concatenation of lists L1 and L2.
This should read concatenate(L1, L2, T) and is the standard append/3 predicate. It corresponds to Haskell's (++) function for list concatenation. For example, it should behave as follows:
?- concatenate([], [1, 2, 3], T).
T = [1, 2, 3].
?- concatenate([1, 2], [3, 4], T).
T = [1, 2, 3, 4].
singletons(P, Q) is true if and only if Q is equivalent to the list obtained from P if each item in P is wrapped in "[" and "]" to create a singleton list.
It looks like this should behave as follows:
?- singletons([foo, bar, baz, 42], Singletons).
Singletons = [[foo], [bar], [baz], [42]].
You may find this easier to do if you first define an auxiliary predicate that only wraps a single term in a list:
?- singleton(foo, Q).
Q = [foo].
?- singleton(foo, [foo]).
true.
(You do not need to use this in your definition of singletons/2, writing it might just clarify part of the problem.)
prefix_all(I, P, Q) is true if and only if P is a list of lists and Q is the list obtained by prepending I to each element in P.
The meaning of this depends on what "prepending" is supposed to mean, but the word prefix suggests that I is to be interpreted as a list that will be the prefix of any list in Q. So something like:
?- prefix_all([pre, fix], [[1, 2], [], [foo, bar, baz]], Q).
Q = [[pre, fix, 1, 2], [pre, fix], [pre, fix, foo, bar, baz]].
Once again, it may help to think about what it means to be the prefix of one list:
?- prefix_one([pre, fix], [1, 2], Xs).
Xs = [pre, fix, 1, 2].
Do not define this predicate! Think about what it means in terms of what you already know.
pairs_all(I, P, Q) is true if and only if Q is the list obtained by pairing I with each item in P.
This looks like it's meant to behave something like this:
?- pairs_all(foo, [1, 2, three, 4], Pairs).
Pairs = [ (foo, 1), (foo, 2), (foo, three), (foo, 4)].
Again, it may help to first define an auxiliary that constructs a single pair:
?- pair(foo, 5, Pair).
Pair = (foo, 5).
Tried before, but it is still kind of a mess for me. Thought it was longest subsequence, but it actually isn't. So writing it with better examples. I am trying to write a Prolog predicate to compare two strings to see if they have the same elements and to print them out (only once per member). Currently I have written this to get the strings into 2 different lists for easier checking:
However, I am having trouble finding the right way to compare EVERY element in those two lists no matter where they are. I have found ways to compare till it founds one and it returns true, but I need it to compare every element in both lists and output them. I know it has to do with heads and comparing them, then adding the next first list member as the new head etc. But I can't figure out a way to do it. Also, intersection kinda does what I need, but it gives me every element (even mutliple times). I need it to stop after it finds the matching element so it finds them all only once.
plates(X,Y,Mem,Num):-
atom_chars(X,Xs),
atom_chars(Y,Ys),
compare_list(Xs,Ys,Mem),
length(Mem,Num).
compare_list([], _, []).
compare_list([H1|T1], L, R) :-
(check_element(H1, L)
->R = [H1|R]
;R = R
),
compare_list(T1, L, R).
check_element(_, []).
check_element(X, [H|T]) :-
X = H,
check_element(X, T).
Example1:
?-plates('111AXB','112XXX', Mem, Num).
Should output:
Mem = ['1','1','X'],
Num = 3.
Example2:
?-plates('456XYZ','678ABC', Mem, Num).
Should output:
Mem = ['6'],
Num = 1.
I tried implementing the solution here:
PROLOG Comparing 2 lists
My test:
?- plates('ABC123','123ABC',Mem,Num).
My output:
Mem = [],
Num = 0.
Expected:
Mem = ['A', 'B', 'C', '1', '2', '3'],
Num = 6.
But I couldn't get it to work the way I wanted it to...
Any help would be very appreciated!
You could write something like:
plates(X,Y,Mem,Num):-
atom_chars(X,Xs),
atom_chars(Y,Ys),
inter(Xs,Ys,Mem),
length(Mem,Num),!.
inter(_,[],[]).
inter([],_,[]).
inter([H|T],L,[H|T1]):-
member(H,L),
delete(H,L,L1),
inter(T,L1,T1).
inter([H|T],L,List):- \+member(H,L),inter(T,L,List).
delete(H,[H|T],T).
delete(H,[X|T1],[X|T]):-dif(H,X),delete(H,T1,T).
Where inter finds the intersection and by checking if an element of first list occurs in second and then adds it to third list and deletes it from the second.Some examples:
?- plates('112XXX','111AXB', Mem, Num).
Mem = ['1', '1', 'X'],
Num = 3.
?- plates('111AXB','112XXX', Mem, Num).
Mem = ['1', '1', 'X'],
Num = 3.
?- plates('456XYZ','678ABC', Mem, Num).
Mem = ['6'],
Num = 1.
?- plates('ABC123','123ABC',Mem,Num).
Mem = ['A', 'B', 'C', '1', '2', '3'],
Num = 6.
?- plates('123ABC','345DEF',Mem,Num).
Mem = ['3'],
Num = 1.
I am looking for a function that can efficiently count, for each element in one list, its occurrences in another list. It should return a sorted list of element/count tuples. Here's the specification:
countList :: Ord a => [a] -> [a] -> [(a, Integer)]
countList ['a', 'b', 'c', 'b', 'b'] ['a', 'b', 'x']
== [('a', 1), ('b', 3), ('x', 0)]
length (countList xs ys) == length ys
A naive implementation would be:
countList xs = sort . map (id &&& length . (\ y -> filter (== y) xs))
This is O(n^2). However, since we have Ord a, this could be made a bit faster using a better strategy. We might sort both lists first, and then compare them in a "ladder-climbing" fasion.
For example, here are the two lists sorted. If I were doing it imperatively, I would use two pointers pointing towards the first element in each list:
i
|
xs = ['a', 'b', 'b', 'b', 'c']
ys = ['a', 'b', 'x']
|
j
Then increase i when xs !! i == ys !! j, meanwhile adding one to the counter at position j. When i encounters a new element, find it in ys by increasing j, and then repeat the previous step. This algorithm is O(n*log(n)).
But I can't find a way to achieve the same complexity in a purely functional way, nor did I find any existing function that can achieve what I want. How should I do this in Haskell?
If the 2nd list does not have duplicates, and the 1st list is longer, you may avoid sorting the first list by using Data.Map. This will achieve an n1 log n2 complexity:
import Data.Map (fromList, toList, adjust)
countList :: Ord a => [a] -> [a] -> [(a, Int)]
countList l r = toList $ foldr (adjust (+1)) (fromList . zip r $ repeat 0) l
I think this accomplishes what you're looking for:
import Data.List (sort)
countList :: Ord a => [a] -> [a] -> [(a, Int)]
countList l1 l2 = countList' (sort l1) (sort l2)
where countList' _ [] = []
countList' xs (y:ys) = let xs' = dropWhile (< y) xs
(a,b) = span (== y) xs'
in (y, length a) : countList' b ys
main = print $ countList ['a', 'b', 'c', 'b', 'b'] ['a', 'b', 'x']