Group a list of tuples by their 1st element - list

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

Related

How to create all possible combinations of these two lists?

I'd like to take from these two lists to create a list of all combinations, where each combination is also a list.
E.g.
Given two lists: [1,2,3] and [True, False]
Combinations:
[(1, False), (2, False), (3, False)]
[(1, False), (2, False), (3, True )]
[(1, False), (2, True ), (3, False)]
[(1, True ), (2, False), (3, False)]
[(1, False), (2, True ), (3, True )]
[(1, True ), (2, False), (3, True )]
[(1, True ), (2, True ), (3, False)]
[(1, True ), (2, True ), (3, True )]
There should be 2^n combinations where n is the number of numbers.
EDIT:
Tried to do the following:
[(n, b) | n <- [1,2,3], b <- [True, False]]
(,) <$> [1,2,3] <*> [True, False]
We can avoid using length, which might be unsafe, since the list can have infinite length. By using recursion or a foldr pattern, we avoid that:
{-# LANGUAGE TupleSections #-}
allComb :: [b] -> [a] -> [[(a,b)]]
allComb vs = go
where go [] = [[]]
go (x:xs) = (:) <$> map (x,) vs <*> go xs
or with a foldr-pattern in a one-liner:
allComb :: [b] -> [a] -> [[(a,b)]]
allComb vs = foldr (\x -> ((:) <$> map (x,) vs <*>)) [[]]
For example:
Prelude> allComb [False, True] [1,2,3]
[[(1,False),(2,False),(3,False)],[(1,False),(2,False),(3,True)],[(1,False),(2,True),(3,False)],[(1,False),(2,True),(3,True)],[(1,True),(2,False),(3,False)],[(1,True),(2,False),(3,True)],[(1,True),(2,True),(3,False)],[(1,True),(2,True),(3,True)]]
The above approach will not work on infinite lists, although we can, given the first list contains at least one element, slightly alter the code, to generate the first element of the result: a list that zips all the elements in the second list with that item. I leave that as an exercise.
This can't be the most straightforward or most efficient answer.
But using the technique from How to generate a list of all possible strings from shortest to longest we can generate a list of all possible Boolean sequences. We take the ones that are the same length as the second list and then zip them with that list.
allBoolPermutations :: Int -> [[Bool]]
allBoolPermutations n = takeWhile (\l -> length l == n)
$ dropWhile (\l -> length l < n)
$ allBools
where
allBools = [ c : s | s <- []:allBools, c <- [True, False]]
zipWithBoolPermutations :: [a] -> [[(a, Bool)]]
zipWithBoolPermutations someList = map (zip someList)
(allBoolPermutations (length someList))
Then zipWithBoolPermutations [1,2,3] should give you what you want.
Your desired output can be produced by defining
foo :: [a] -> [b] -> [[(a, b)]]
foo nums bools =
map (zip nums) . sequence $ replicate (length nums) bools
=
let n = length nums
in
[ zip nums bs | bs <- sequence $ replicate n bools]
and calling
foo [1,2,3] [False, True]
That call is equivalent to
let nums = [1,2,3]
bools = [False, True]
n = 3
in
[ zip nums bs | bs <- sequence $ replicate n bools]
=
[ zip [1,2,3] bs | bs <- sequence $ replicate 3 [False, True]]
=
[ zip [1,2,3] (b:bs) | b <- [False, True]
, bs <- sequence $ replicate 2 [False, True]]
=
[ zip [1,2,3] (b:c:bs) | b <- [False, True]
, c <- [False, True]
, bs <- sequence $ replicate 1 [False, True]]
=
[ zip [1,2,3] (b:c:d:bs) | b <- [False, True]
, c <- [False, True]
, d <- [False, True]
, bs <- sequence $ replicate 0 [False, True] ]
=
[ zip [1,2,3] (b:c:d:bs) | b <- [False, True]
, c <- [False, True]
, d <- [False, True]
, bs <- sequence [] ]
=
[ zip [1,2,3] (b:c:d:bs) | b <- [False, True]
, c <- [False, True]
, d <- [False, True]
, bs <- [[]] ]
=
[ zip [1,2,3] (b:c:d:[]) | b <- [False, True]
, c <- [False, True]
, d <- [False, True] ]
i.e.
[ zip [1,2,3] [b,c,d] | b <- [False, True]
, c <- [False, True]
, d <- [False, True] ]
and if evaluate this last expression, we also get the same result.
Filling up the three spaces with each possible combination of the two available values is like having all possible functions from 3 spaces to 2 values, whatever those spaces and values are.
Mathematicians write this function as 23, and indeed, we get 2^3 = 8 outputs.
edit: the sequence ... replicate combo is actually just reimplementing another built-in, replicateM:
foo ns bs = map (zip ns) (replicateM (length ns) bs)
because replicateM n a is just like sequence (replicate n a), but without actually building the intermediate list.
For the pointfree aficionados, we can thus have
foo ns = map (zip ns) . replicateM (length ns)
= (.) ((map . zip) ns) ((replicateM . length) ns)
= ((.) . map . zip <*> replicateM . length) ns
i.e.
foo = (.) . map . zip <*> replicateM . length
Nice and short:
traverse ((<$> [True, False]) . (,)) [1,2,3]
Or less pointfree, but perhaps more understandable:
traverse (\x -> [(x,True), (x,False)]) [1,2,3]
The inner function ((<$> [True, False]) . (,) or \x -> [(x,True), (x,False)]) takes each element such as 1 and turns it into [(1,True),(1,False)]. If you think of traverse f as being sequence . fmap f, then the fmap f part means do that function to each thing in the list (yielding [[(1,True),(1,False)],[(2,True),(2,False)],[(3,True),(3,False)]]), and the sequence part means combine them with the List applicative (which models non-determinism) to create all possible combinations (yielding [[(1,True),(2,True),(3,True)],[(1,True),(2,True),(3,False)],[(1,True),(2,False),(3,True)],[(1,True),(2,False),(3,False)],[(1,False),(2,True),(3,True)],[(1,False),(2,True),(3,False)],[(1,False),(2,False),(3,True)],[(1,False),(2,False),(3,False)]]).

Turn adjacency list into tuple array Haskell

Let's say I have the following input:
[(0, [1, 2]) , (2, [3, 4]) , (4, [])
This is an adjacency list and I want to convert it as such:
[(0,1), (0,2), (2,3), (2, 4)] -- notice how there is no 4 mapping to anything
Here is what I have so far:
conv :: [(Int, [Int])] -> [(Int, Int)]
conv adj = map fn adj -- mapping (0, [1, 2]) should give me [(0, 1), (0, 2)]
fn:: (Int, [Int]) -> [(Int, Int)]
fn (rt, list) = -- somehow perform [(rt, l[0]), (rt, l[1]) ...]
List comprehension can do the trick:
conv :: [(a, [b])] -> [(a, b)]
conv xys = [(x, y) | (x, ys) <- xys, y <- ys ]
Or we can use concatMap here:
conv :: Foldable f => f (a, [b]) -> [(a, b)]
conv = concatMap (uncurry (map . (,)))
Here the inner function uncurry (map . (,)) takes a tuple (x, ys) and thus performs a map (x,): the uncurry basically unpacks the tuple (x, ys), and calls (map . (,)) x ys, so that means that we obtain (map (x,)) ys. The above syntax uses the TupleSections extension, but we do not need to activate that extension in the real program, since we never write such syntax. Your fn function you defined is thus equivalent to uncurry (map . (,)).
We thus use this function in a concatMap that will pass the 2-tuples, and concatenate the lists these individual tuples create.
or we can use the "bind" >>= :: Monad m => m a -> (a -> m b) -> m b function:
conv :: Monad m => m (a, m b) -> m (a, b)
conv = (=<<) (\(x, ys) -> ys >>= return . (x,))
or shorter:
conv :: Monad m => m (a, m b) -> m (a, b)
conv = (=<<) (uncurry (fmap . (,)))
the nice thing about the latter is that it also works with Maybes, etc. For example:
Prelude> conv [(0, [1, 2]) , (2, [3, 4]) , (4, [])]
[(0,1),(0,2),(2,3),(2,4)]
Prelude> conv Nothing
Nothing
Prelude> conv (Just (3, Nothing))
Nothing
Prelude> conv (Just (3, Just 2))
Just (3,2)
Taking advantage of instance Traversable ((,) a), we have this remarkably short (and remarkably inscrutable) solution:
conv :: [(Int, [Int])] -> [(Int, Int)]
conv = (sequence =<<)
The most general type of (sequence =<<) is (Monad m, Traversable t) => m (t (m a)) -> m (t a).

Haskell - separate a list of pairs in two lists using fold

So, I am given a list containing tuples and I need to break it down into two lists, the first list containing the elements with odd index and the second list containing the elements with even index, must be done using fold, here is my attempt:
breakList :: [(Integer, Integer)] -> [[(Integer, Integer)]]
breakList [] = [[], []]
breakList xxs#(x:xs) = foldl (\ acc y -> if length (acc !! 0) < length (acc !! 1) then y : (acc !! 0) else y : (acc !! 1) ) [[], []] xxs
Error I am getting:
Couldn't match type '(Integer, Integer)'
with '[(Integer, Integer)]'
Expected type: [[(Integer, Integer)]]
when hovering over y : (acc !! 1) and y : (acc !! 0)
Example:
Input:
ex1 = [ (2, 2), (1, 3), (2, 3), (2, 4), (3, 5), (0, 2), (2, 1), (1, 4)
, (2, 0), (1, 2), (3, 1), (1, 0)]
Output
breakList ex1
== ( [(2,2),(2,3),(3,5),(2,1),(2,0),(3,1)] , [(1,3),(2,4),(0,2),(1,4),(1,2),(1,0)])
The standard trick here, as hinted at by Willem in the comments, which I first saw few years back on SO in an (F# or Ocaml) answer by [user:Ed'ka], is
evenodds :: [a] -> ([a], [a])
evenodds xs = foldr g ([],[]) xs
where
g x ~(as,bs) = (bs,x:as)
or
oddevens :: [a] -> ([a], [a])
oddevens xs = foldr g ([],[]) xs
where
g x ~(bs,as) = (x:as,bs)
What are odd positions from here, are even positions from the position one notch further on the list.
The tilde ~ introduces a lazy pattern so that the function is properly lazy in its operations.
Note that you want to split a list into two lists of a pair, so the return type should be
([(Integer, Integer)], [(Integer, Integer)])
not
[[(Integer, Integer)]]
and access the element of pair, you can use fst and snd instead of through index, and finally, use foldl will return the resulted list in reversed order, it can be fixed use foldr instead. The correction look like:
breakList :: [(Integer, Integer)]->([(Integer, Integer)], [(Integer, Integer)])
breakList xxs = foldr (\y acc-> if length (fst acc) < length (snd acc)
then (y:(fst acc), snd acc)
else (fst acc, y:(snd acc)) ) ([], []) xxs

Intersection of lists of tuples - Haskell

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)]

Sort a multimap with respect to another list?

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