I am wondering why the following call of groupBy does not work: My predicate is x < y, so I expect [1, 6] to be a group, but instead, Haskell put [1, 6, 4, 2] into a group.
Prelude Data.List> groupBy (\x y -> x < y) [8,5,3,2,1,6,4,2]
[[8],[5],[3],[2],[1,6,4,2]]
More strangely, when I change the last number to -2, I expect the same behavior as in the above example. That is, since both 2 and -2 are less than 4, I expect that in the result [1, 6, 4, -2] would make up a group. But instead, This time, Haskell put -2 to be a group.
Prelude Data.List> groupBy (\x y -> x < y) [8,5,3,2,1,6,4,-2]
[[8],[5],[3],[2],[1,6,4],[-2]]
Do I have a wrong understanding of groupBy?
In the implementation of the groupBy, x is always the first item of the sublist. Indeed, groupBy is implemented as:
groupBy :: (a -> a -> Bool) -> [a] -> [[a]]
groupBy _ [] = []
groupBy eq (x:xs) = (x:ys) : groupBy eq zs
where (ys,zs) = span (eq x) xs
especially the span (eq x) is important here, since x will be the first item of a new group.
Since x is thus not the previous value in the list. If we thus run groupBy with the list [5, 3, 2, 1, 6, 4, -2], we get:
list
current list
x=?
check with
outcome
[5,3,2,1,6,4,-2]
[8]
8
/
/
[5,3,2,1,6,4,-2]
[8]
8
5
False
[3,2,1,6,4,-2]
[5]
5
/
/
[3,2,1,6,4,-2]
[5]
5
3
False
[3,2,1,6,4,-2]
[3]
3
/
/
[2,1,6,4,-2]
[3]
3
2
False
[2,1,6,4,-2]
[2]
2
1
False
[1,6,4,-2]
[2]
2
/
/
[1,6,4,-2]
[2]
2
1
False
[6,4,-2]
[1]
1
/
/
[4,-2]
[1,6]
1
6
True
[-2]
[1,6,4]
1
4
True
[]
[-2]
-2
/
/
Especially the case where we compare x=1 and y=4 is important. If x was only the previous value, we should start generating a new list, but since x is the first item of the list, that is not the case.
Normally you should only work with an equivalence relation ~ [wiki], such relation is:
reflexive: so x ~ x is true;
symmetric: so x ~ y if and only if y ~ x; and
transitive: so x ~ y and y ~ z implies that x ~ z.
Your equivalence relation is not reflexive, nor is it symmetric. This is thus not a valid function to work with groupBy.
The conceptual definition of groupBy p l is that it yields sublists of l such that for each xs in l, you have
all (==True) [p x y | x<-xs, y<-xs]
IOW, each sublist should be part of an equivalence class of p. That notion only makes sense if p is an equivalence relation. In particular, you need p x y ≡ p y x, and the defining equation also assumes that p x x is always true.
The implementation in the standard libraries shows that idea quite clearly: each x:ys list in the result has ys defined by the span of elements that are equivalent to x by the relation. So in your case, you get 1:[6,4,2], where 6,4,2 are all greater than 1.
Evidently, groupBy doesn't actually check p x y for all pairs of elements in the result lists, so this really only makes sense if p is indeed an equivalence relation.
What you expected the idea to be – and IMO this is not unreasonable – is that only for all x,y such that x is the left neighbour of y, you want p x y to hold. This is in general a weaker condition, but if p is an equivalence relation then it actually implies the original condition, because such a relation also is transitive. So maybe the implementation should actually be
groupBy' :: (a -> a -> Bool) -> [a] -> [[a]]
groupBy' _ [] = []
groupBy' _ (x:l) = (x:xs) : zss
where (xs,zss) = case l of
[] -> ([],[])
zs#(y:_)
-> let ys:zss' = groupBy' p zs
in if p x y then (ys, zss')
else ([], ys:zss')
(This could be simplified a bit, but then it wouldn't be as lazy as the old implementation.)
Related
This question already has answers here:
Generating integers in ascending order using a set of prime numbers
(4 answers)
Closed 4 years ago.
I am trying to generate a list of all multiples which can be represented by the form , where a, b, and c are whole numbers. I tried the following,
[ a * b * c | a <- map (2^) [0..], b <- map (3^) [0..], c <- map (5^) [0..] ]
but it only lists powers of 5 and never goes on to 2 or 3.
Edit: My apologies, it seems that I did not clarify the question enough. What I want is an ordered infinite list, and while I could sort a finite list, I feel as if there may be a solution that is more efficient.
The reason why there are only powers of 5 is that Haskell tries to evaluate every possible c for a = 2^0 and b = 3^0 and only when it is finished it goes for a = 2^0 and b = 3^1.
So this way you can only construct a finite list like this:
[ a * b * c | a <- map (2^) [0..n], b <- map (3^) [0..n], c <- map (5^) [0..n] ]
for a given n.
My first idea was starting from lists of powers of 2, 3 and 5, respectively:
p2 = iterate (2 *) 1
p3 = iterate (3 *) 1
p5 = iterate (5 *) 1
It's also easy to merge two sorted streams:
fuse [] ys = ys
fuse xs [] = xs
fuse xs#(x : xs') ys#(y : ys')
| x <= y = x : fuse xs' ys
| otherwise = y : fuse xs ys'
But then I got stuck because fuse p2 (fuse p3 p5) doesn't do anything useful. It only produces multiples of 2, or 3, or 5, never mixing factors.
I couldn't figure out a purely generative solution, so I added a bit of filtering in the form of a set accumulator. The algorithm (which is quite imperative) is:
Initialize the accumulator to {1}.
Find and remove the smallest element from the accumulator; call it n.
Emit n.
Add {2n, 3n, 5n} to the accumulator.
Go to #2 if you need more elements.
The accumulator is a set because this easily lets me find and extract the smallest element (I'm using it as a priority queue, basically). It also handles duplicates that arise from e.g. computing both 2 * 3 and 3 * 2.
Haskell implementation:
import qualified Data.Set as S
numbers :: [Integer]
numbers = go (S.singleton 1)
where
go acc = case S.deleteFindMin acc of
(n, ns) -> n : go (ns `S.union` S.fromDistinctAscList (map (n *) [2, 3, 5]))
This works, but there are things I don't like about it:
For every element we emit (n : ...), we add up to three new elements to the accumulator (ns `S.union` ... [2, 3, 5]). ("Up to three" because some of them may be duplicates that will be filtered out.)
That means numbers carries around a steadily growing data structure; the more elements we consume from numbers, the bigger the accumulator grows.
In that sense it's not a pure "streaming" algorithm. Even if we ignore the steadily growing numbers themselves, we need more memory and perform more computation the deeper we get into the sequence.
From your code:
[ a * b * c | a <- map (2^) [0..], b <- map (3^) [0..], c <- map (5^) [0..] ]
Since map (5^) [0..] is an infinite list, upon first iterations of a and b, it iterates over the said infinite list, which won't halt. That's why it is stuck at powers of 5.
Here is a solution apart from arithmetics. Note that map (2^) [0..], map (3^) [0..], and map (5^) [0..] are all lists sorted in ascending order. That means the usual merge operation is applicable:
merge [] ys = ys
merge xs [] = xs
merge (x:xs) (y:ys) = if x <= y then x : merge xs (y:ys) else y : merge (x:xs) ys
For convenience, let xs = map (2^) [0..]; let ys = map (3^) [0..]; let zs = map (5^) [0..].
To get multiples of 2 and 3, consider the following organization of said numbers:
1, 2, 4, 8, 16, ...
3, 6, 12, 24, 48, ...
9, 18, 36, 72, 144, ...
...
Judging by this, you might hope the following works:
let xys = foldr (merge . flip fmap xs . (*)) [] ys
But this doesn't work, because from the organization above, merge doesn't know which row contains the resulting head element, infinitely leaving it unevaluated. We know that the upper row contains said head element, so with following little tweak, it finally works:
let xys = foldr ((\(m:ms) ns -> m : merge ms ns) . flip fmap xs . (*)) [] ys
Do the same against zs, and here comes the desired list:
let xyzs = foldr ((\(m:ms) ns -> m : merge ms ns) . flip fmap xys . (*)) [] zs
Full code in summary:
merge [] ys = ys
merge xs [] = xs
merge (x:xs) (y:ys) = if x <= y then x : merge xs (y:ys) else y : merge (x:xs) ys
xyzs = let
xs = map (2^) [0..]
ys = map (3^) [0..]
zs = map (5^) [0..]
xys = foldr ((\(m:ms) ns -> m : merge ms ns) . flip fmap xs . (*)) [] ys
in foldr ((\(m:ms) ns -> m : merge ms ns) . flip fmap xys . (*)) [] zs
but it only lists powers of 5 and never goes on to 2 or 3.
Addressing only this bit.
To calculate numbers 2^a*3^0b*5^c you tried generating the triples (a,b,c), but got stuck producing those of the form (0,0,c). Which is why your numbers are all of the form 2^0*3^0*5^c, i.e. only powers of 5.
It's easier if you start with pairs. To produce all pairs (a,b) you can work along the diagonals of the form,
a+b = k
for each positivek. Each diagonal is easy to define,
diagonal k = [(k-x,x) | x <- [0..k]]
So to produce all pairs you'd just generate all diagonals for k<-[1..]. You want triples (a,b,c) though, but it's similar, just work along the planes,
a+b+c = k
To generate such planes just work along their diagonals,
triagonal k = [(k-x,b,c) | x <- [0..k], (b,c) <- diagonal x]
And there you go. Now just generate all 'triagonals' to get all possible triples,
triples = [triagonal k | k <- [0..]]
The other way to look at it is you wanted the numbers which are only divisible by 2,3 or 5. So check if each number starting from 1 satisfies this condition. If yes it is part of the list.
someList = [x| x<- [1..], isIncluded x]
where isIncluded is the function which decides whether x satisfies the above condition. To do this isIncluded divides the number first by 2 till it can not be divided any further by 2. Then same it does with new divided number for 3 and 5. It at ends there is 1 then we know this number is only divisible by 2,3 or 5 and nothing else.
This may not be the fastest way but still the simplest way.
isIncluded :: Int -> Bool
isIncluded n = if (powRemainder n 2 == 1) then True
else let q = powRemainder n 2
in if (powRemainder q 3 == 1) then True
else let p = powRemainder q 3
in if (powRemainder p 5 == 1) then True else False;
powRemainder is the function which takes number and base and returns the number which can not be further divided by base.
powRemainder :: Int -> Int -> Int
powRemainder 1 b = 1
powRemainder n b = if (n `mod` b) == 0 then powRemainder (n `div` b) b else n
with this when I run take 20 someList it returns [1,2,3,4,5,6,8,9,10,12,15,16,18,20,24,25,27,30,32,36].
As others already commented, your core does not work because it is analogous to the following imperative pseudocode:
for x in 0..infinity:
for y in 0..infinity:
for z in 0..infinity:
print (2^x * 3^y * 5^x)
The innermost for takes infinite time to execute, so the other two loops will never get past their first iteration. Consequently, x and y are both stuck to value 0.
This is a classic dovetailing problem: if we insist on trying all the values of z before taking the next y (or x), we get stuck on a subset of the intended outputs. We need a more "fair" way to choose the values of x,y,z so that we do not get stuck in such way: such techniques are known as "dovetailing".
Others have shown some dovetailing techniques. Here, I'll only mention the control-monad-omega package, which implements an easy to use dovetailing monad. The resulting code is very similar to the one posted in the OP.
import Control.Monad.Omega
powersOf235 :: [Integer]
powersOf235 = runOmega $ do
x <- each [0..]
y <- each [0..]
z <- each [0..]
return $ 2^x * 3^y * 5^z
How can I write a powerList function in Haskell like the following? I would like it to build such a list with n multiply operations, where each element is a simple multiple of the previous element, not n exponent operations.
Ideally, the implementation is clean, idiomatic Haskell, and reasonably efficient.
-- powerList x n -> [1, x, x^2, ..., x^n]
-- For example:
-- powerList 2 0 -> [1]
-- powerList 2 1 -> [1, 2]
-- powerList 2 2 -> [1, 2, 4]
-- powerList 2 3 -> [1, 2, 4, 8]
-- powerList 2 4 -> [1, 2, 4, 8, 16]
powerList :: forall a. Integral a => a -> a -> [a]
powerList _ 0 = [1]
powerList x n = [] -- ???
For a list where each element is a function of the previous element, you can use iterate:
iterate :: (a -> a) -> a -> [a]
iterate f x returns an infinite list of repeated applications of f to x:
iterate f x == [x, f x, f (f x), ...]
Prelude> powerList x n = take (n + 1) $ iterate (* x) 1
Prelude> powerList 2 0
[1]
Prelude> powerList 2 4
[1,2,4,8,16]
If you wanted to not use iterate or take for practice, I'd start by looking at how iterate is implemented:
iterate f i = i : iterate f (f i)
To do something similar, our recursive function will need an additional parameter i. This is a pretty common technique when writing recursive functions.
-- powerList x n = [ 1, x, x^2, ..., x^n ]
powerList x n = powerList' n 1
where
-- powerList' n i = [ i, i*x, i*x^2, ..., i*x^n ]
powerList' 0 i = [ i ]
powerList' n i = i : powerList' (n - 1) (i * x)
List comprehensions are often a shorthand for generators. Generators are used in other functions for many purposes. List comprehensions are often succinct enough to include in-line in a function. The following is a list comprehension version of your powerList function. It is simply named p. I'm lazy.
Two values in the result are a Cartesian product of each with each. The constant that is also the first parameter is needed only once. Go figure.
Prelude> p i j = [(k ^ n) | k <- [i], n <- [0..j]]
Prelude> p 2 16
[1,2,4,8,16,32,64,128,256,512,1024,2048,4096,8192,16384,32768,65536]
LOL a glaring fact, the i or k is a constant and a parameter, ready to use.
p i j = [(i ^ n) | n <- [0..j] ]
What I find most remarkable about Haskell is that functions like above are specifications rather than directives. Many Haskell functions tell the computer what is wanted instead of what to do to get it, that is, it's greatly declarative which is what is most wanted in a language.
Edit 4/5/2018
I am so sorry. Your specification to multiply the last value by a factor was not met by my last functions. Your specification is literally recursive. "where each element is a simple multiple of the previous element, not n exponent operations." The following function does exactly that.
pow l = l ++ pow [(last l) * 2]
But like iterate, is infinite. Use take x $ pow [1] to not have it run forever.
Chris's answer is most likely what you're looking for.
If you'd like to do it without the use of iterate, you can use the following code.
Edit : to avoid appending to the tail of the list (which takes linear time), one can use an auxiliary function powerList' to first compute the list in reverse then reverse the output of that function to correct the order.
powerList' :: Integral a => a -> a -> [a]
powerList' _ 0 = [1]
powerList' x n = do { let l = go x (n - 1)
; [x * (head l)] ++ l
}
powerList :: Integral a => a -> a -> [a]
powerList x n = reverse (powerList' x n)
Given a list like:
[1, 2, 2, 6, 7, 8, 10, 11, 12, 15]
Split it into blandly increasing ranges (maybe equal):
[[1, 2, 2], [6, 7, 8], [10, 11, 12], [15]]
I tried using a recursive approach:
splitRanges [] = [[]]
splitRanges (x:y:xs)
| x `elem` [y, y + 1] = [x, y] : splitRanges xs
| otherwise = xs
So if the item is one less or equal to the item after I fuse them. But it says I am trying to build an infinite type:
Occurs check: cannot construct the infinite type: a0 = [a0]
Expected type: [[a0]]
Actual type: [a0]
But what does [the fact that it is monotone] have to do with how the list is split?
That being strictly increasing would give different results.
Or are you really trying to say something else?
I hope I am not.
Will the list always be monotone?
No, splitting a monotone list means making it into just one sub-list.
If not, how should that affect the results?
If it is not monotone, you will have many sublists.
Is it always brown into groups of three?
No, the groups may contain n elements.
More examples would be good
splitRanges [1, 3] == [[1], [3]]
splitRanges [1, 2, 5] == [[1, 2], [3]]
splitRanges [0, 0, 1] == [[0, 0, 1]]
splitRanges [1, 5, 7, 9] == [[1], [5], [7], [9]]
I appreciate hints rather than full answers, as I would like to improve myself, copy-pasting is not improvement.
Try breaking the problem into more manageable parts.
First, how would you split just one blandly increasing range from the start of a list? Lets guess that should be splitOne :: [Integer] -> ([Integer], [Integer]).
Second, how can you repeatedly apply splitOne to the left-over list? Try implementing splitMany :: [Integer] -> [[Integer]] by using splitOne.
For splitOne, what should you be trying to find? The first position to split at. What are "split positions"? Lets make that up.
split 0 1 2 3 4 …
list [ | x1, | x2, | x3, | x4, | x5, …]
So a split at 0 is ([], [x1,x2,x3,x4,x5,…]), and a split at 3 is ([x1,x2,x3],[x4,x5,…]). What relationship can you see between the split position and the split list?
How do you determine the first split position of the list? Lets say that is implemented as firstSplitPos :: [Integer] -> Integer. What is the first split position of an empty list?
Can you now implement splitOne using firstSplitPos?
One Possible Answer
-- What are the adjacencies for:
-- 1) empty lists?
-- 2) lists with one element?
-- 3) lists with more than one element?
--
-- Bonus: rewrite in point-free form using <*>
--
adjacencies :: [a] -> [(a,a)]
adjacencies xxs = zip xxs (drop 1 xxs)
-- Bonus: rewrite in point-free form
--
withIndices :: [a] -> [(Int,a)]
withIndices xxs = zip [0..] xxs
-- This is the most involved part of the answer. Pay close
-- attention to:
-- 1) empty lists
-- 2) lists with one element
-- 3) lists which are a blandly increasing sequence
--
firstSplitPos :: (Eq a, Num a) => [a] -> Int
firstSplitPos xxs = maybe (length xxs) pos (find q searchList)
where q (_,(a,b)) = a /= b && a + 1 /= b
searchList = withIndices (adjacencies xxs)
-- Why is the split position one more than the index?
pos (i,_) = i + 1
--
-- Bonus: rewrite in point-free form using <*>
--
splitOne :: (Eq a, Num a) => [a] -> ([a],[a])
splitOne xxs = splitAt (firstSplitPos xxs) xxs
splitMany :: (Eq a, Num a) => [a] -> [[a]]
-- What happens if we remove the case for []?
splitMany [] = []
splitMany xxs = let (l, r) = splitOne xxs in l : splitMany r
Another Approach
This is my explanation of Carsten's solution. It is already succinct but I have elected for a variation which does not use a 2-tuple.
We know that Haskell lists are defined inductively. To demonstrate this, we can define an equivalent data type.
data List a = Cons a (List a) -- Cons = (:)
| Nil -- Nil = []
Then ask the question: can we use induction on lists for the solution? If so, we only have to solve two cases: Cons and Nil. The type signature of foldr shows us exactly that:
foldr :: (a -> b -> b) -- Cons case
-> b -- Nil case
-> [a] -- The list
-> b -- The result
What if the list is Nil? Then the only blandly increasing sequence is the empty sequence. Therefore:
nilCase = [[]]
We might want nilCase = [] instead, as that also seems reasonable — i.e. there are no blandly increasing sequences.
Now you need some imagination. In the Cons case we only get to look at one new element at a time. With this new element, we could decide whether it belongs to the right-adjacent sequence or if it begins a new sequence.
What do I mean by right-adjacent? In [5,4,1,2,2,7], 1 belongs to the right-adjacent sequence [2,2].
How might this look?
-- The rest of the list is empty
consCase new [] = [new] : []
-- The right-adjacent sequence is empty
consCase new ([]:ss) = [new] : ss
-- The right-adjacent sequence is non-empty
-- Why `new + 1 == x` and not `new == x + 1`?
consCase new sss#(xxs#(x:_):ss)
| new == x || new + 1 == x = (new:xxs):ss
| otherwise = [new]:sss
Now that we solved the Nil case and the Cons case, we are done!
splitRanges = foldr consCase nilCase
It would be useful and idiomatic to write your function to take a predicate, instead of writing your split condition into the function itself:
splitBy2 :: (a -> a -> Bool) -> [a] -> [[a]]
splitBy2 ok xs = snd $ f xs [] []
where f (a:b:xs) acc_list acc_out_lists | ok a b = ...
I hope you don't mind spoiling part of it, but as the comments are discussing what you want (and I hope I've got it) maybe you are interested in another possible solution?
I don't want to spoil it all but I think you can easily work this out:
blandly :: (Ord a, Num a) => [a] -> [[a]]
blandly = g . foldr f ([],[])
where f x ([],xss) = ([x],xss)
f x (y:ys,xss)
| abs (x-y) <= 1 = undefined
| otherwise = undefined
g (ys,xss) = undefined
you just have to fill in the undefined holes
The idea is just to fold the list from the right, accumulating your inner lists in the first item of the tuple, s long as the elements are not to far away; and if they are: to push it to the second item.
If done correctly it will yield:
λ> blandly [1,3]
[[1],[3]]
λ> blandly [1,2,5]
[[1,2],[5]]
λ> blandly [0,0,1]
[[0,0,1]]
λ> blandly [1,5,7,9]
[[1],[5],[7],[9]]
which seems to be what you want
1 hour later - I think I can post my solution - just stop reading if you don't want to get spoiled
blandly :: (Ord a, Num a) => [a] -> [[a]]
blandly = uncurry (:) . foldr f ([],[])
where f x ([],xs) = ([x],xs)
f x (y:ys,xs)
| abs (x-y) <= 1 = (x:y:ys,xs)
| otherwise = ([x],(y:ys):xs)
maybe I have a slight misunderstanding here (the examples did not specify it) - but if you want on only monotonic increasing inner lists you just have to change the abs part:
blandly :: (Ord a, Num a) => [a] -> [[a]]
blandly = uncurry (:) . foldr f ([],[])
where f x ([],xss) = ([x],xss)
f x (y:ys,xss)
| 0 <= y-x
&& y-x <= 1 = (x:y:ys,xss)
| otherwise = ([x],(y:ys):xss)
I want to compare each item in the list of lists with other elements, for example,
[[1,2,3], [0,2,2], [1,4,5], [3,1,1]]
compare [1,2,3] to [0,2,2] and applying an operation (for example, the formula of distance "sqrt ((x2-x1)^2+(y2-y1)^2)" and the result of that operation evaluate it with a guard), then compare the [1,2,3] to [1,4,5] and so end the list, then with [0 , 2.2] to [1,4,5] etc ...
I was thinking about taking (head i) and tail (head i) to compare, but do not know how to continue iterating comparisons
can you guys give me an idea about how i can do this? thank you
edit
what i need is this, with the first list of list i need to make another list of list's based on the distance formula and comparing the 3rd element of the list, for example
[[1,2,3], [0,2,2], [1,4,5], [3,1,1]]
[x1,y1,z1], [x2,y2,z2]
sqrt ((x2-x1)^2+(y2-y1)^2)) if result_of_sqrt < z1 then 1:[do the same thing with the other element]
else 0:[do the same thing with the other element]
sqrt ((0-1)^2+(2-2)^2) ) = 1, 1 < 3 => 1:(compare this two elements [1,2,3],[1,4,5]) and so...
The question is really unclear, but it sounds like, at a fundamental level, you want to take each element of a list and compare it to all of the rest of elements in the list. Say we want to pair all of the elements in [1..3] where order doesn't matter, i.e. we want the list:
`[(1, 2), (1, 3), (2, 3)]`
We can do this directly:
pairAll :: [a] -> [(a, a)]
pairAll [] = []
pairAll (x:xs) = map (\y -> (x, y)) xs ++ pairAll xs
Now pairAll [1..3] == [(1, 2), (1, 3), (2, 3)] as desired. We can factor out the pairing function to get:
doStuffToAll :: (a -> a -> b) -> [a] -> [b]
doStuffToAll _ [] = []
doStuffToAll f (x:xs) = map (f x) xs ++ doStuffToAll f xs
And then pairAll = doStuffToAll (\x y -> (x, y)).
Replace the lambda expression with your comparison function for lists (i.e. doStuffWithAll compareLists), and that should do it, if I understand your question properly.
This seems to produce your last example result:
f xs = map (\x -> map (test x) xs) xs
where test a#[x1,y1,z1] b#[x2,y2,z2] =
if a == b
then 0
else if sqrt ((x2 - x1) ^ 2 + (y2 - y1) ^ 2) < z1
then 1
else 0
Or with guards instead of if and else:
f xs = map (\x -> map (test x) xs) xs
where test a#[x1,y1,z1] b#[x2,y2,z2]
| a == b = 0
| m < z1 = 1
| otherwise = 0
where m = sqrt ((x2 - x1) ^ 2 + (y2 - y1) ^ 2)
Output:
*Main> f [[0,0,4], [2,4,2], [1,3,5], [3,1,1]]
[[0,0,1,1],[0,0,1,0],[1,1,0,1],[0,0,0,0]]
I'm not sure if I've understood you correctly, but perhaps this will help you figure something out:
Pair up all the tuples
Apply your 'comparison' function to those tuples and output a true/false
.
lol :: [(Int,Int,Int)]
lol = [(1,2,3), (0,2,2), (1,4,5), (3,1,1)]
-- Use list comprehension to get all your unique pairs
tuples = [(x,y) | x <- lol, y <- lol, x > y]
result = map myCompare tuples
-- myCompare takes a tuple of two 3-vector tuples and does an operation on them
-- It outputs the two vectors it and a True/False
myCompare (x#(x1,y1,z1),y#(x2,y2,z2)) = if ( (x1-x2)^2 + (y1-y2)^2 < (z2-z1)^2 ) then (x,y,True) else (x,y,False)
Outputs:
tuples = [((1,2,3),(0,2,2)),((1,4,5),(1,2,3)),((1,4,5),(0,2,2)),((3,1,1),(1,2,3)),((3,1,1),(0,2,2)),((3,1,1),(1,4,5))]
result = [((1,2,3),(0,2,2),False),((1,4,5),(1,2,3),False),((1,4,5),(0,2,2),True),((3,1,1),(1,2,3),False),((3,1,1),(0,2,2),False),((3,1,1),(1,4,5),True)]
I have 3 lists of type ::[Integer] , which are sorted from smallest to largest ,all of arbitrary and different lengths, what would be the most efficient way to find all common integers, if any exist, in all 3 lists.
I don't know if this is the fastest but should be pretty fast. Uses the fact that the lists or ordered.
repeats :: [Integer] -> [Integer] -> [Integer] -> [Integer]
repeats [] _ _ = []
repeats _ [] _ = []
repeats _ _ [] = []
repeats a#(x:xs) b#(y:ys) c#(z:zs)
| x == y && y == z = x : repeats xs ys zs
| x <= y && x <= z = repeats xs b c
| y <= x && y <= z = repeats a ys c
| otherwise = repeats a b zs
If the first element of all the lists is the same then we add that to the list of repeats. Otherwise we discard the least value of any of the lists are then recurse. If you had n lists you would probably need a binary heap or something.
EDIT
tail recursive version
repeatsTail :: [Integer] -> [Integer] -> [Integer] -> [Integer]
repeatsTail f s t = go f s t []
where go [] _ _ acc = reverse acc
go _ [] _ acc = reverse acc
go _ _ [] acc = reverse acc
go a#(x:xs) b#(y:ys) c#(z:zs) acc
| x == y && y == z = go xs ys zs (x:acc)
| x <= y && x <= z = go xs b c acc
| y <= x && y <= z = go a ys c acc
| otherwise = go a b zs acc
EDIT 2:
With as patterns
The most concise way would probably be to use the function Data.List.intersect:
import Data.List (intersect)
intersect [1, 2, 3] (intersect [1, 2] [2, 3])
The problem with this solution is that intersect has to traverse the lists more than once in order to find matching elements.
If you want to avoid this overhead, you have to store the elements in a more efficient data structure, at least temporarily. The obvious and probably reasonably efficient solution would be to convert to sets and use Data.Set.intersection:
import Data.Set (fromList, toList, intersection)
toList (intersection (fromList [1, 2, 3]) (intersection (fromList [1, 2]) (fromList [2, 3])))
If the elements of the list are small enough to fit into Int (instead of Integer), you could use Data.IntSet instead of Data.Set to improve the performance:
import Data.IntSet (fromList, toList, intersection)
toList (intersection (fromList [1, 2, 3]) (intersection (fromList [1, 2]) (fromList [2, 3])))
If you need more performance, you have to choose a data structure that is appropriate for the numbers in your lists. Maybe bitsets work for your use case? Or you could try to use UArray Int Boolean with the accumArray function somehow.
For short lists, I would simply build something using elem. You could maybe exploit the insight that any number which appears in all three lists has to appear in the shortest list: so you only need to consider all numbers in the shortest list.
For longer lists, I'd convert the lists to IntSet and then use intersection:
import Data.IntSet
intersection3 :: [Int] -> [Int] -> [Int] -> [Int]
intersection3 a b c = toList $ fromAscList a `intersection` fromAscList b `intersection` fromAscList c
This seems to work pretty fast too:
import Data.List (sort,group)
f a b c = map head
. filter (not . null . drop 2)
. group
. sort
$ a ++ b ++ c