I have two lists of tuples both of the form [(a,b),..].
I wish to compare them and get the common elements - but have tried using intersect, but this does not work. Is there a way of using map/filter to output the intersection as a new list of tuples?
Try with a list comprehension:
[x | x <- list1, x `elem` list2]
Example:
Prelude> let list1 = [(1,2), (2,3), (3,4)]
Prelude> let list2 = [(1,2), (2,3), (3,5)]
Prelude> [x | x <- list1, x `elem` list2]
[(1,2),(2,3)]
Anyway, intersect should work, it works for me:
Prelude> import Data.List
Prelude Data.List> list1 `intersect` list2
[(1,2),(2,3)]
You can use Data.Function.on function to supply function you need to the first (or second) element of the tuple:
import Data.Function (on)
import Data.List (intersectBy)
intersectBy ((==) `on` fst) [(1,2), (2,3), (3,4)] [(1,2), (2,3), (3,5)]
> [(1,2),(2,3),(3,4)]
Related
My code as below
(value, index) = maximumBy (comparing fst) (zip list [0..])
works fine in most cases, however, in case of a tie, it returns the index that is closest to the tail, which is the opposite of what I want.
Namely, if the list is xs = [2,7,3,7], I want it to return (7,1) instead of (7,3). Is there an easy way to do it, or I need to rewrite it completely?
Is there an easy way to do it, or do I need to rewrite it completely ?
If you insist on reusing the library maximumBy function, you can do it this way: replace the fst argument to comparing by something more appropriate.
For example, negate the indices to have the comparison result go the opposite way.
λ>
λ> xs = [2,7,3,7]
λ>
λ> maximumBy (comparing (\(v,x) -> (v,-x))) (zip xs [0..])
(7,1)
λ>
If you are familiar with the Haskell Arrow facility, the same idea can be expressed in more concise fashion:
λ>
λ> import Control.Arrow
λ>
λ> maximumBy (comparing (second id)) (zip xs [0..])
(7,3)
λ>
λ> maximumBy (comparing (second negate)) (zip xs [0..])
(7,1)
λ>
λ> maximumBy (comparing (id *** negate)) (zip xs [0..])
(7,1)
λ>
This is the source code for maximumBy
maximumBy :: Foldable t => (a -> a -> Ordering) -> t a -> a
maximumBy cmp = foldl1 max'
where max' x y = case cmp x y of
GT -> x
_ -> y
So by definition it returns the rightmost max element.
The most straightforward way to get the leftmost max element, I suppose, would be to define your own maximumBy' like so
maximumBy' cmp = fold1 max'
where max' x y = case cmp x y of
LT -> y
_ -> x
All other ways redefine max in some way, much like how we did here.
That would give you:
> maximumBy' (comparing fst) (zip xs [0..])
> (7,1)
I want to write a function which takes a input list and manipulates it in the following way:
Step 1: Take the first element of the list and the last element of the list and put it together in a sublist.
Step 2: Take the second element of the list and the second last element of the list and put it together in the next sublist.
Step 3: Take the third element of the list and the third last element of the
list and put it together in next sublist.
Continue this according to the same scheme (for a list of n elements)...
If the number of elements of the input list is odd the n/2 element of the input list will be added as last sublist of the output list.
Example:
[1,2,3,4,5,6,7]
-- should be transformed to
[[1,7],[2,6],[3,5],[4]]
I already wrote a function which takes every 2 elements of a list and puts it together in sublists and I am wondering if this code might help me with my problem above:
g2 :: [a] -> [[a]]
g2 [] = []
g2 (x1:x2:xs) = [x1,x2]: g2 xs
g2 xs = [xs]
Here's one that does it in one pass:
pairs :: [a] -> [[a]]
pairs xs = fst (go xs xs) where
go (x:xs) (_:_:ys) = f x (go xs ys)
go (x:xs) [_] = ([[x]],xs)
go xs [] = ([],xs)
f x (xs,y:ys) = ([x,y]:xs,ys)
How does it work? Let's look at the first two arguments of go first, and in particular this line:
go (x:xs) (_:_:ys) = f x (go xs ys)
Those two arguments are both from the same list (xs), but we take 2 items off of one, and only one off of the other. Why? So we know when we hit the halfway point. Look at this function for comparison:
halfway xs = go xs xs
where
go (_:xs) (_:_:ys) = go xs ys
go xs _ = xs
>>> halfway [1..6]
[4,5,6]
Now, once we get to the halfway point we'll need to "zip" it with the other list. But it needs to be in reverse! How do we do this? A handy way to reverse any function in one pass is to first write it as a fold. Here's zip written as a fold:
zip = foldr (\x k (y:ys) -> (x,y) : k ys) (const [])
To "reverse" it, you just apply is as a foldl rather than as a foldr (you also have to flip the closure).
For our uses, we basically build up the base as we go (in the form of k). So no our function looks like this:
pairs :: [a] -> [[a]]
pairs xs = go xs xs (const []) where
go (y:ys) (_:_:zs) k = go ys zs (f y k)
go (y:ys) [_] k = [y] : k ys
go ys [] k = k ys
f x k (y:ys) = [x,y] : k ys -- same `f` as from `zip`
There's still one problem: the list is returned in the wrong order. To fix this, we replace the list with a difference list, and swap the order of the appends.
Finally, we un-CPS the function, and we get the above.
Here's one using transpose
import Data.List
g2 xs =
transpose [take (x + y) xs, take x (reverse xs)]
where (x, y) = (length xs) `divMod` 2
Note that we have to use drop 1 instead of tail here to avoid errors for odd-length lists.
g2 :: [a] -> [[a]]
g2 [] = []
g2 xs = [first xs] ++ (g2 . drop 1 $ init xs)
where first (x:[]) = [x]
first xs = [head xs, last xs]
Two more, the second is using unfoldr:
pair xs = take (length xs `div` 2) $ zip xs (reverse xs)
-- Note: uses tuples instead of lists
import Data.List
pairs2 = unfoldr (\xs ->
if length xs < 2
then Nothing
else Just ([head xs, last xs], init.tail $ xs))
xs = [2,3,4,7,6]
pair xs -- [(2,6),(3,7)]
pair2 xs -- [[2,6],[3,7]]
Say I have a tuple list that consists of [("ab", 1), ("ab", 2), ("ac", 3)]
Using the group function would split this list into a list of lists of tuples like so:
[
[("ab", 1)],
[("ab", 2)],
[("ac", 3)]
]
How would you group the tuple ignoring one of the indices so that they'd be grouped based on one of the elements:
[
[("ab", 1), ("ab", 2)],
[("ac", 3]
]
Would the groupBy function be needed in this case?
Use Data.List groupBy function (docs):
Prelude> import Data.List
Prelude Data.List> let xs = [("ab", 1), ("ab", 2), ("ac", 3)]
Prelude Data.List> groupBy (\a b -> fst a == fst b) xs
[[("ab",1),("ab",2)],[("ac",3)]]
or as suggested by #dfeuer:
...
import Data.Function
groupBy ((==) `on` fst) xs
How can I do the sum of elements in a list at the same position?
For example:
[[2,3,4],[5,6,7],[8,9,10]]=[15,18,21]
Thanks
Try:
sumIn :: Num a => [[a]] -> [a]
sumIn = foldl (zipWith (+)) (repeat 0)
Note that if the argument is an empty list, the result is an infinite list of zeros. So you may want to treat this case separately, for example
sumIn :: Num a => [[a]] -> [a]
sumIn [] = []
sumIn xs = foldl (zipWith (+)) (repeat 0) xs
Here's an example in GHCi:
λ> let xs = [[2,3,4],[5,6,7],[8,9,10]]
λ> foldr1 (zipWith (+)) xs
[15,18,21]
You could transpose the list, and sum each list in the result:
ghci> import Data.List (transpose)
ghci> map sum $ transpose [[2,3,4],[5,6,7],[8,9,10]]
[15,18,21]
Unlike the other solutions, this works for lists of non-uniform length.
Given a certain order of keys, how can I sort a multimap (list of tuples with duplicate keys) with respect to this list, where the order of duplicate elements doesn't matter?
I'm looking for a function with the following signature
sortByList :: [(a,b)] -> [a] -> [(a,b)]
such that, for instance,
a = [(1,'a'), (2, 'b'), (102, 'c'), (2, 'z')]
b = [2,102,1]
sortByList a b -- [(2,'b'), (2,'z'), (102, 'c'), (1, 'a')]
-- or [(2,'z'), (2,'b'), (102, 'c'), (1, 'a')]
-- (order in duplicate keys irrelevant)
I have some ideas how to implement this, but they all seem ugly and cumbersome (using lookup and repeated find-and-delete on the given multimap).
I think this should be fairly optimal:
import Data.List
import Data.Ord
import qualified Data.Map as M
sortByList :: Ord a => [(a, b)] -> [a] -> [(a, b)]
sortByList xs ys = map snd $ sortBy (comparing fst) [(pos (fst x), x) | x <- xs]
where order = M.fromList $ zip ys [1..]
pos x = M.findWithDefault 0 x order
If xs has length n and ys has length m, the run time of this should be O(n log n + (m + n) log m), which is O(n log n) if m is O(n).
elemIndex is the function you need:
import Data.List (sortBy, elemIndex)
import Data.Function (on)
sortByList :: Eq a => [(a,b)] -> [a] -> [(a,b)]
sortByList m as = sortBy (compare `on` (flip elemIndex as . fst)) m
It puts the keys which are not in the list in front, because Nothing < Just 0.
Here's a far from optimal suggestion:
import Data.List
sortByList :: (Eq a) => [(a,b)] -> [a] -> [(a,b)]
sortByList toSort order = reverse (go [] toSort order)
where
go result xs [] = xs ++ result
go result xs (k:ks) = go (matches ++ result) unmatches ks
where
(matches, unmatches) = partition ((==k) . fst) xs
import Data.List
sortByList::(Ord a,Ord b)=>[(a,b)]->[a]->[(a,b)]
sortByList m [] = m
sortByList m (x:xs) = sort(filter (\(a,b)->a==x) m)++ sortByList (filter (\(a,b)->a/=x) m) xs
Ugly code but it works
import Data.List
sortByList::(Ord a,Ord b)=>[(a,b)]->[a]->[(a,b)]
sortByList m [] = m
sortByList m (x:xs) = let t = filter (\(a,b)->a==x) m in sort t ++ sortByList (m\\t) xs