Create a list from data and keys - list

I have a question about Haskell. I want to know how I can create a list of data from two lists, one with data, an other with some key values. I'll explain it with an example:
Given two lists: [('a', "red"), ('b', "blue"), ('c', "green")] and [('a','b'), ('b', 'c'), ('c','a')]. Now I want to change the values of the second list with their colors given in the first list. So the function should return [("red","blue"), ("blue","green"), ("blue","red")].
I was thinking about list comprehension, but I'm very new to Haskell and I have no idea how I should do that. Or is there an easier way to do this?
This is probably a dumb question, but if someone can give me an example, I might get used to the think process of Haskell a bit more.

Another way would be to use Map
import Data.Maybe (mapMaybe)
import Data.Map (lookup
,fromList)
import Prelude hiding (lookup)
main :: IO ()
main = do
let a = [('a', "red"), ('b', "blue"), ('c', "green")]
b = [('a','b'), ('b', 'c'), ('c','a')]
table = fromList a
print $ mapMaybe (maybePair . (\(x,y) -> (x `lookup` table,
y `lookup` table ))) b
maybePair :: (Maybe a, Maybe b) -> Maybe (a,b)
maybePair (Just x,Just y) = Just (x, y)
maybePair _ = Nothing
Edit:
with the help of arrows the last anonymous function can be condensed to
import Control.Arrow ((***))
[…]
main :: IO ()
main = do
let a = [('a', "red"), ('b', "blue"), ('c', "green")]
b = [('a','b'), ('b', 'c'), ('c','a')]
table = fromList a
f x = x `lookup` table
print $ mapMaybe (maybePair . (f *** f)) b
[…]

-- second element from first (head) dropping tuples with bad key
color :: Eq a => a -> [(a, b)] -> b
color c = snd.head.dropWhile ((/=c).fst)
recolor a b = map (\(x, y) -> (color x a, color y a)) b
running
Prelude> recolor [('a', "red"), ('b', "blue"), ('c', "green")] [('a','b'), ('b', 'c'), ('c','a')]
[("red","blue"),("blue","green"),("green","red")]
If you consider an element of the second list cannot be found in the first list. You can write
color :: Eq b => b -> [(b, a)] -> Maybe a
color c = fmap snd.listToMaybe.dropWhile ((/=c).fst)
then
Prelude> recolor [('a',"red"),('b',"blue"),('c',"green")] [('a','h'),('u','c'),('c','a')]
[(Just "red",Nothing),(Nothing,Just "green"),(Just "green",Just "red")]
(you need import Data.Maybe (listToMaybe))

Another solution without need of importing any library but using tail recursion:
keyColor = [('a', "red"), ('b', "blue"), ('c', "green")]
keys = [('a','b'), ('b', 'c'), ('c','a')]
colors [] _ = [] -- no keys returns the empty list
colors _ [] = [] -- no colors returns the empty list
colors xs ys = colors_helper (xs, ys, []) -- tail recursion
colors_helper ([], _, acc) = acc
colors_helper (((k1, k2):xs), ys, acc) =
colors_helper (xs, ys, acc ++ [(color (k1, ys), color (k2, ys))])
where
-- converts value to color
color (val, ys) = snd $ head $ filter ( \(k, v) -> k == val ) ys
test:
> colors keys keyColor
> [("red","blue"),("blue","green"),("green","red")]
> colors keys []
> []
> colors [] keyColor
> []

Related

Cut list before last element that is equal to parameter

I need a function:
splitOn :: (Eq p) => p -> [p] -> ([p], [p])
So that:
splitOn 'b' ['a', 'b', 'b', 'b', 'c', 'a'] = (['a', 'b', 'b'], ['c', 'a'])
splitOn 'b' ['a', 'b', 'c', 'a'] = (['a'], ['c', 'a'])
The argument passed is guaranteed to be in a consecutive block in the middle.
Is there a way to do splitOn on a single pass through the list?
Sorry if this is a duplicate, I couldn't find a way to search it.
First we do this, then we do that, and then we stop:
splitOn :: Eq a => a -> [a] -> ([a], [a])
splitOn b xs = g xs
where
g [] = ([], [])
g (x:xs) | x==b = f xs
| otherwise = first (x:) $ g xs
f [] = ([], [])
f (x:xs) | x==b = first (x:) $ f xs
| otherwise = ([], x:xs)
From my vague understanding, it sounds like you have a set of points you want to store in a somewhat balanced binary search tree indexed by the first components. To take an off-the-shelf balanced binary search tree, this could look something like the following:
{-# LANGUAGE DeriveFoldable #-}
import Data.Map.Strict (Map)
import qualified Data.Map.Strict as M
import Data.Set (Set)
import qualified Data.Set as S
-- | A `PointTree` stores, for each `a`, a set of second
-- components `b`.
newtype PointTree a b = PT
{ getPT :: Map a (Set b) }
fromList :: (Ord a, Ord b) => [(a, b)] -> PointTree a b
fromList = PT . M.fromListWith Set.union . map S.singleton
toList :: PointTree a b -> [(a, b)]
toList (PT m) = [(a, b) | (a, bs) <- M.assocs m, b <- S.elems bs]
The above will discard duplicate points. If you want to keep those, you can use lists instead of sets.
Now if you want to build your very own balanced tree, you'll have to pick one. Data.Map and Data.Set use Adams trees (approximately weight-balanced). You could also use AVL trees, red-black trees, etc.

How would you use map on a list of tuples that contains a list of tuples?

I have a list here that has the following structure:
list = [((1,1),[("A", 1), ("D", 4), ("E", 5)]), ((2,2),[("B", 2)]), ((3,3),[("C",3)])]
I want to output a list that has the following structure (aka summing the values of each of the second values of each sublist so for example (1+4+5) = 10
[((1,1),10), ((2,2),2), ((3,3),3))]
I am not sure how to get that structure by using map or even filter and the closest I have gotten is:
map snd (concat (map snd list))
which produces [1,4,5,2,3]
How would I achieve this structure?
First, write out the types:
have :: [((Int,Int), [(String,Int)])]
have = [ ((1,1),[("A", 1), ("D", 4), ("E", 5)]), ... ]
want :: [((Int,Int), Int)]
Evidently, the (Int,Int) isn't really relevant here, nor is the String. So our conversion function can be
give :: [(a, [(b, Int)])] -> [(a, Int)]
Furthermore, the a is just passed as-is, so the interesting bit is going to be [(b, Int)] -> Int. For this, you first need to throw away the bs
Prelude> map snd [("A", 1), ("D", 4), ("E", 5)]
[1,4,5]
and sum the result (composition!)
Prelude> sum . map snd $ [("A", 1), ("D", 4), ("E", 5)]
10
So sum . map snd is the function you'll need to apply to every RHS in the list of outer tuples.
How do you actually use it on only the RHS? Well, one way is to write a lambda
\(x,y) -> (x, f y)
...but actually there's a standard combinator for this, called second
second :: (b -> c) -> (d,b) -> (d,c)
(operating on the snd element of a tuple, applying a function† to it, putting it back in the tuple).
Prelude Control.Arrow> second (sum . map snd) (346, [("A", 1), ("D", 4), ("E", 5)])
(346,10)
All that's left to do is mapping that whole thing over the outer list:
Prelude Control.Arrow> map (second $ sum . map snd) [((1,1),[("A", 1), ("D", 4), ("E", 5)]), ((2,2),[("B", 2)]), ((3,3),[("C",3)])]
[((1,1),10),((2,2),2),((3,3),3)]
Or as a definition
give :: Num c => [(a, [(b, c)])] -> [(a, c)]
give = map . second $ sum . map snd
†If you look in the docs you'll find that second is actually more general than that: it can work not only with functions, but general arrows ~>, i.e. second :: Arrow (~>) => (b ~> c) -> ((d,b)~>(d,c)). If that's confusing to you, don't worry... in most applications, the arrow will just be the normal function one.
If you don't mind the map you could use list comprehension here:
list = [((1,1),[("A",1),("D",4),("E",5)]),((2,2),[("B",2)]),((3,3),[("C",3)])]
[(fst x, sum [snd y | y <- (snd x) ]) | x <- list]
returns
[((1,1),10),((2,2),2),((3,3),3)]

Combine tuples based on first element (Haskell) [duplicate]

Given a list of tuples like this:
dic = [(1,"aa"),(1,"cc"),(2,"aa"),(3,"ff"),(3,"gg"),(1,"bb")]
How to group items of dic resulting in a list grp where,
grp = [(1,["aa","bb","cc"]), (2, ["aa"]), (3, ["ff","gg"])]
I'm actually a newcomer to Haskell...and seems to be falling in love with it..
Using group or groupBy in Data.List will only group similar adjacent items in a list.
I wrote an inefficient function for this, but it results in memory failures as I need to process a very large coded string list. Hope you would help me find a more efficient way.
Whenever possible, reuse library code.
import Data.Map
sortAndGroup assocs = fromListWith (++) [(k, [v]) | (k, v) <- assocs]
Try it out in ghci:
*Main> sortAndGroup [(1,"aa"),(1,"cc"),(2,"aa"),(3,"ff"),(3,"gg"),(1,"bb")]
fromList [(1,["bb","cc","aa"]),(2,["aa"]),(3,["gg","ff"])]
EDIT In the comments, some folks are worried about whether (++) or flip (++) is the right choice. The documentation doesn't say which way things get associated; you can find out by experimenting, or you can sidestep the whole issue using difference lists:
sortAndGroup assocs = ($[]) <$> fromListWith (.) [(k, (v:)) | (k, v) <- assocs]
-- OR
sortAndGroup = fmap ($[]) . M.fromListWith (.) . map (fmap (:))
These alternatives are about the same length as the original, but they're a bit less readable to me.
Here's my solution:
import Data.Function (on)
import Data.List (sortBy, groupBy)
import Data.Ord (comparing)
myGroup :: (Eq a, Ord a) => [(a, b)] -> [(a, [b])]
myGroup = map (\l -> (fst . head $ l, map snd l)) . groupBy ((==) `on` fst)
. sortBy (comparing fst)
This works by first sorting the list with sortBy:
[(1,"aa"),(1,"cc"),(2,"aa"),(3,"ff"),(3,"gg"),(1,"bb")]
=> [(1,"aa"),(1,"bb"),(1,"cc"),(2,"aa"),(3,"ff"),(3,"gg")]
then grouping the list elements by the associated key with groupBy:
[(1,"aa"),(1,"bb"),(1,"cc"),(2,"aa"),(3,"ff"),(3,"gg")]
=> [[(1,"aa"),(1,"bb"),(1,"cc")],[(2,"aa")],[(3,"ff"),(3,"gg")]]
and then transforming the grouped items to tuples with map:
[[(1,"aa"),(1,"bb"),(1,"cc")],[(2,"aa")],[(3,"ff"),(3,"gg")]]
=> [(1,["aa","bb","cc"]), (2, ["aa"]), (3, ["ff","gg"])]`)
Testing:
> myGroup dic
[(1,["aa","bb","cc"]),(2,["aa"]),(3,["ff","gg"])]
Also you can use TransformListComp extension, for example:
Prelude> :set -XTransformListComp
Prelude> import GHC.Exts (groupWith, the)
Prelude GHC.Exts> let dic = [ (1, "aa"), (1, "bb"), (1, "cc") , (2, "aa"), (3, "ff"), (3, "gg")]
Prelude GHC.Exts> [(the key, value) | (key, value) <- dic, then group by key using groupWith]
[(1,["aa","bb","cc"]),(2,["aa"]),(3,["ff","gg"])]
If the list is not sorted on the first element, I don't think you can do better than O(nlog(n)).
One simple way would be to just sort and then use anything from the answer of second part.
You can use from Data.Map a map like Map k [a] to use first element of tuple as key and keep on adding to the values.
You can write your own complex function, which even after you all the attempts will still take O(nlog(n)).
If list is sorted on the first element as is the case in your example, then the task is trivial for something like groupBy as given in the answer by #Mikhail or use foldr and there are numerous other ways.
An example of using foldr is here:
grp :: Eq a => [(a,b)] -> [(a,[b])]
grp = foldr f []
where
f (z,s) [] = [(z,[s])]
f (z,s) a#((x,y):xs) | x == z = (x,s:y):xs
| otherwise = (z,[s]):a
{-# LANGUAGE TransformListComp #-}
import GHC.Exts
import Data.List
import Data.Function (on)
process :: [(Integer, String)] -> [(Integer, [String])]
process list = [(the a, b) | let info = [ (x, y) | (x, y) <- list, then sortWith by y ], (a, b) <- info, then group by a using groupWith]

Haskell pair of a number and list

I have a problem. I have a task that can't solve on my own. Here is the deal:
extPair :: Eq a => [(a,b)] -> [(a,[b])]
If I want to call this with:
extPair [(3,"pear"),(3,"fog"),(4,"dog"),(4,"x"),(3,"y")]
Should give the following result:
[(3, ["pear", "fog"]), (4, ["dog", "x"]), (3, ["y"])] :: [(Integer, [[Char]])]
All I know now is:
extPair [] = []
extPair (x:xs)
| length (x:xs) >= 2 && fst x == fst (head xs) = [(fst x, [snd x, snd (head xs)])] ++ extPair (drop 1 xs)
| otherwise = [(fst x, [snd x])]
This works fine for the example, but it doesn't work on the following, and I don't know how to make it, so I ask Your help. I would like to add as many pairs as I want like:
extPair [(3,"pear"),(3,"fog"),(3,"dark"),(3,"etc"), ... ,(4,"dog"),(4,"x"),(3,"y"),(3,"z")]
So the result should be:
[(3, ["pear", "fog", "dark", "etc", "...", "...", ...]), (4, ["dog", "x"]), (3, ["y", "z"])] :: [(Integer, [[Char]])]
Yet another solution using the foldr function:
extPair :: Eq a => [(a,b)] -> [(a,[b])]
extPair = foldr f []
where
f (key, elem) [] = [(key, [elem])]
f (key1, elem) l#((key2, elems):xs)
| key1 == key2 = (key2,elem:elems):xs
| otherwise = (key1,[elem]):l
You can start by pre-processing the list with groupBy:
> import Data.List
> import Data.Function
> groupBy ((==) `on` fst) [(3,"pear"),(3,"fog"),(4,"dog"),(4,"x"),(3,"y")]
[[(3,"pear"),(3,"fog")],[(4,"dog"),(4,"x")],[(3,"y")]]
From there, use map f for a suitable f.
If you instead want to write your own code, consider recursion:
extPair ((n,s):xs) = ???
where ys = extPair xs
the logic here would something like: if ys starts with (n,zs), then prepend s to zs, otherwise prepend (n,[s]) to ys.

Haskell - how to iterate list elements in reverse order in an elegant way?

I'm trying to write a function that given a list of numbers, returns a list where every 2nd number is doubled in value, starting from the last element. So if the list elements are 1..n, n-th is going to be left as-is, (n-1)-th is going to be doubled in value, (n-2)-th is going to be left as-is, etc.
So here's how I solved it:
MyFunc :: [Integer] -> [Integer]
MyFunc xs = reverse (MyFuncHelper (reverse xs))
MyFuncHelper :: [Integer] -> [Integer]
MyFuncHelper [] = []
MyFuncHelper (x:[]) = [x]
MyFuncHelper (x:y:zs) = [x,y*2] ++ MyFuncHelper zs
And it works:
MyFunc [1,1,1,1] = [2,1,2,1]
MyFunc [1,1,1] = [1,2,1]
However, I can't help but think there has to be a simpler solution than reversing the list, processing it and then reversing it again. Could I simply iterate the list backwards? If yes, how?
The under reversed f xs idiom from the lens library will apply f to xs in reverse order:
under reversed (take 5) [1..100] => [96,97,98,99,100]
When you need to process the list from the end, usually foldr works pretty well. Here is a solution for you without reversing the whole list twice:
doubleOdd :: Num a => [a] -> [a]
doubleOdd = fst . foldr multiplyCond ([], False)
where multiplyCond x (rest, flag) = ((if flag then (x * 2) else x) : rest, not flag)
The multiplyCond function takes a tuple with a flag and the accumulator list. The flag constantly toggles on and off to track whether we should multiply the element or not. The accumulator list simply gathers the resulting numbers. This solution may be not so concise, but avoids extra work and doesn't use anything but prelude functions.
myFunc = reverse
. map (\(b,x) -> if b then x*2 else x)
. zip (cycle [False,True])
. reverse
But this isn't much better. Your implementation is sufficiently elegant.
The simplest way to iterate the list backwards is to reverse the list. I don't think you can really do much better than that; I suspect that if you have to traverse the whole list to find the end, and remember how to get back up, you might as well just reverse it. If this is a big deal, maybe you should be using some other data structure instead of lists—Vector or Seq might be good choices.
Another way to write your helper function is to use Traversable:
import Control.Monad.State
import Data.Traversable (Traversable, traverse)
toggle :: (Bool -> a -> b) -> a -> State Bool b
toggle f a =
do active <- get
put (not active)
return (f active a)
doubleEvens :: (Num a, Traversable t) => t a -> t a
doubleEvens xs = evalState (traverse (toggle step) xs) False
where step True x = 2*x
step False x = x
yourFunc :: Num a => [a] -> [a]
yourFunc = reverse . doubleEvens
Or if we go a bit crazy with Foldable and Traversable, we can try this:
Use Foldable's foldl to extract a reverse-order list from any of its instances. For some types this will be more efficient than reversing a list.
Then we can use traverse and State to map each element of the original structure to its counterpart in the reversed order.
Here's how to do it:
import Control.Monad.State
import Data.Foldable (Foldable)
import qualified Data.Foldable as F
import Data.Traversable (Traversable, traverse)
import Data.Map (Map)
import qualified Data.Map as Map
toReversedList :: Foldable t => t a -> [a]
toReversedList = F.foldl (flip (:)) []
reverse' :: Traversable t => t a -> t a
reverse' ta = evalState (traverse step ta) (toReversedList ta)
where step _ = do (h:t) <- get
put t
return h
yourFunc' :: (Traversable t, Num a) => t a -> t a
yourFunc' = reverse' . doubleEvens
-- >>> yourFunc' $ Map.fromList [(1, 1), (2, 1), (3, 1), (4, 1)]
-- fromList [(1,2),(2,1),(3,2),(4,1)]
-- >>> yourFunc' $ Map.fromList [(1, 1), (2, 1), (3, 1)]
-- fromList [(1,1),(2,2),(3,1)]
There's probably a better way to do this, though...
func xs = zipWith (*) xs $ reverse . (take $ length xs) $ cycle [1,2]