Trying to work out a solution to this problem..
Let's say I have x = fromList[("a", 1), ("b", 2), ("c", 3)]
And have a list ["a", "a", "b", "c" , "c"]
How would I think about producing something like..
Map.fromList[("a", 2), ("b", 2), ("c", 6)]
Any help leading in the right direction would be greatly appreciated
I'm starting from the assumption in K. A. Buhr's comment that you want to obtain the product of the counts in the original hash and the hash originating from the input list.
For this we need a function occurrences which transforms a list of strings into a hash from string to number of occurrences. This can easily be done using the insertWith function, which combines a the value to be inserted with the stored values using the given operation if a stored value exists and otherwise just inserts.
To multiply the occurrences with the existing hash, we use the unionWith function which works in a similar way as insertWith in the sense that it forms the union using a given operation if the element exists in both hashes and otherwise just inserts.
{-# OPTIONS_GHC -Wall #-}
import Data.Map
x :: Map String Int
x = fromList [("a", 1), ("b", 2), ("c", 3)]
occurrences :: Ord k => [k] -> Map k Int
occurrences l = aux l empty
where
aux [] h = h
aux (a:as) h = aux as $ insertWith (+) a 1 h
main :: IO ()
main = print $ unionWith (*) x $ occurrences ["a", "a", "b", "c", "c"]
Live example on Wandbox
Related
I'm new to Haskell and I'm currently trying to solve a little problem.
I want to create a function occurrences that is defined as such:
occurrences:: Int -> String -> [[(Char, Int)]]
The function accepts an Int and String as its parameters; where Int represents the number of occurrence lists to be printed. The number of occurrences for each character should be sorted in descending order.
For example, occurrences 2 'hi' should return [[('h', 1), ('i', 1)], [('h', 1), ('i', 1)]] and occurrences 3 'foo' would return [[('o', 2), ('f', 1)], [('o', 2), ('f', 1)], [('o', 2), ('f', 1)]]
So far I've added the below as part of my implementation for the occurrences function.
occurrences str = map (\x -> [(head x, length x)]) $ group $ sort str
But this just prints [[('h',1)],[('i',1)]] rather than [[('h', 1), ('i', 1)]] and I'm not sure how to return n number of lists according to the input as I'm new to Haskell.
Can I get help on this please?
You can convert [[('h',1)],[('i',1)]] to [('h', 1), ('i', 1)] using concat. Once you've done that, you'd want to replicate it the specified number of times.
It works well.
import Data.List
import Data.Ord (comparing)
occurrences n = replicate n . reverse . sortBy (comparing snd) . map (\x -> (head x, length x)) . group . sort
main = print $ occurrences 3 "aabaccaccbbcc"
output:
[[('c',6),('a',4),('b',3)],[('c',6),('a',4),('b',3)],[('c',6),('a',4),('b',3)]]
I have a list of lists in single chars like: [["a"],["b"],["c"],["d"]],
and I have a map for example [("a", "A"), ("b", "B")], I would like to find elements in list that match the map keys and replace the list value with the map value for that key and remove all of the remaining unchanged single chars.
So for example from the above, if I have list of [["a"],["b"],["c"],["d"]] and map of [("a", "A"), ("b", "B")] I want to get back a single list like this: ["A", "B"]
As I am a total noob with Haskell so any help will be appreciated :)
You can combine lookup with catMaybes:
import Data.Maybe
list :: [[String]]
list = [["a"],["b"],["c"],["d"]]
replacements :: [(String, String)]
replacements = [("a", "A"), ("b", "B")]
replaced :: [String]
replaced = catMaybes . map (\x -> lookup x replacements) . concat $ list
main :: IO ()
main = print replaced -- ["A", "B"]
Is there a function in Haskell where say if you supplied a Char, and a List of 13 Pairs of Chars (all different i.e. every letter of the alphabet was used once and only once) it would return you the Char which is paired with your inputted Char i.e. if I inputted the following:
pairedChar Q [(A,Z),(B,Y),(C,X),(D,W),(E,V),(F,U),(G,T),(H,S),(I,R),(J,Q),(K,P),(L,O),(M,N)]
I would like it to return J?
If there isn't a function like that I was thinking maybe of doing it with unzip to get a pair of lists but wasn't sure what to do with the lists after I get them?
The lookup function does this; not just for the kind of pairs you describe but for any list of two-element tuples. A list of such tuples is known as an association list, by the way.
It returns a Maybe, because there might beono match.
lookup :: Eq a => a -> [(a, b)] -> Maybe b
lookup key assocs
looks up a key in an association list
This answer builds on itsbruce's answer by still using lookup, but also first massaging the input list to include each pair twice, once for each ordering of elements.
Let's assume that your list is called pairs:
pairs :: [(Char, Char)]
pairs = [('A', 'Z'), ('B', 'Y'), ..., ('M', 'N')]
Then all you need to do is duplicate each pair and swap the elements:
import Data.Tuple (swap)
allPairs :: [(Char, Char)]
allPairs = pairs ++ map swap pairs
-- allPairs = [('A', 'Z') ... ('M', 'N'), ('Z', 'A'), ... ('N', 'M')]
... where swap is a function from Data.Tuple that takes the two elements of a tuple and swaps them. It's defined like this:
swap :: (a, b) -> (b, a)
swap (x, y) = (y, x)
Now you can do a lookup on the allPairs list:
pairedChar :: Char -> Maybe Char
pairedChar c = lookup c allPairs
If you want each duplicate pair to be adjacent to each other in the list, then you can also write allPairs like this:
allPairs = do
(x, y) <- pairs
[(x, y), (y, x)]
Now it will contain this ordering:
allPairs = [('A', Z'), ('Z', 'A'), ('B', 'Y'), ('Y', 'B') ... ('M', 'N'), ('N', 'M')]
You could just make a longer list.
alphabet = "ABCDEFGHIJKLMNOPQRTSUVXYZ"
pairs = zip alphabet (reverse alphabet)
theOtherChar k = lookup k pairs --does the job for you now.
I have a large nested vector that look like this:
import Data.Vector
let x = fromList [["a", "b", "12", "d"], ["e", "f", "34", "g"]...]
I would like to convert the strings to integers at position 2 in each nested list I was trying to do this with map and a comprehension like this:
let y = Data.Vector.map (\a -> read a :: Int) [i !! 2 | i <- x]
What am I doing wrong? I would like the output to be:
(("a", "b", 12, "d"), ("e", "f", 34, "g")...)
There are a number of problems here.
First of all, the result of a list comprehension is a list, so you're calling Data.Vector.map on a list, which won't work. And the x inside the comprehension is a Vector, which is another type mismatch. Either use a list instead of a Vector (along with Prelude.map) or convert the list to a Vector (in which case you can't use a list comprehension).
Secondly, ignoring the list/Vector problem, [i !! 2 | i <- x] will give you a list containing only the elements at position 2 from each sub-list. Using your example, the comprehension would yield ["12", "34"]. Then when you map read over it, you'll get [12, 34], rather than the output you're shooting for.
Finally, the output you're wanting to see is not valid for lists or for Vectors in Haskell. Both types of container must be homogeneous, i.e. they cannot contain values of more than one type. A [Int] cannot contain Strings, nor can a [String] contain Ints, but your desired output contains both. There are ways you can get around this using existential types, but chances are there's a better solution for your underlying problem than to try to build heterogeneous collections.
Edit: You edited the last part of your post to use tuples, so the above paragraph no longer applies. The first two problems I mentioned still exist, though.
If you start with a list of 4-tuples ([(String, String, String, String)]), you can get what you want like this:
> let x = [("a", "b", "12", "d"), ("e", "f", "34", "g")]
> map (\(a, b, c, d) -> (a, b, read c :: Int, d)) x
[("a", "b", 12, "d"), ("e", "f", 34, "g")]
It looks much like you should use a more sophisticated data type than a 4-tuple, like
data YourType_StringNum = YourType_StringNum { ytsnLetters1 :: String
, ytsnLetters2 :: String
, ytsnNumber :: String
, ytsnLetters3 :: String }
data YourType_IntNum = YourType_IntNum { ytinLetters1 :: String
, ytinLetters2 :: String
, ytinNumber :: Int
, ytinLetters3 :: String }
(of course with better identifiers). Then define a function like
toYtin :: YourType_StringNum -> YourType_IntNum
toYtin(YourType_StringNum a b s c) = YourType_IntNum a b (read s) c
With that, your problem reduces to transforming a Vector YourType_StringNum to a Vector YourType_IntNum, and that's trivially done with Data.Vector.map toYtin.
Let's say I have the following type
type Key = String
type Score = Int
data Thing = Thing Key Score
And if I have an array of them like this:
[Thing "a" 7, Thing "b" 5, Thing "a" 10]
Is there a standard way to reduce this so that I don't have any duplicate keys? If two keys match, I want to take the better score
[Thing "b" 5, Thing "a" 10]
A very simple solution is to use Data.Map.fromListWith, which converts a list of key-value pairs to a map, given a function to combine multiple values with the same key.
Prelude Data.Map> fromListWith max [("a", 7), ("b", 5), ("a", 10)]
fromList [("a",10),("b",5)]
Note that this expects tuples, so convert as necessary. Also, it does not preserve the order of the input elements. Run time is O(n log n).
Basically first we must decide what is problem solving and what is implementation difficulties. So what If we first sort by Score, and then just keep the first occurrences in the sorted list with respect to Key? That should work, let's look at the haskell implementation:
import Data.List
import Data.Function
type Key = String
type Score = Int
data Thing = Thing { key :: Key, score :: Score }
deriving (Show)
myNub = nubBy ((==) `on` key)
mySort = sortBy (compare `on` (negate . score))
selectFinest = myNub . mySort
Now we try run this in ghci:
Prelude> :load Test.hs
[1 of 1] Compiling Main ( Test.hs, interpreted )
Ok, modules loaded: Main.
*Main> selectFinest [Thing "a" 7, Thing "b" 5, Thing "a" 10]
[Thing {key = "a", score = 10},Thing {key = "b", score = 5}]
Checkout hoogle if you are uncertain about the functions I used in the solution. It indeed takes some time to learn how to use on and those functions.
I'm posting a O(n log n) solution, since everyone seems fine with being O(n^2)
consolidate :: (Ord a, Ord b) => [Thing a b] -> [Thing a b]
consolidate xs =
max_from_each_group (sortBy (compare `on` getKey) xs)
where
max_from_each_group [] = []
max_from_each_group (x:xs) =
let (same_key, rest) = span (\t -> x == getKey t) xs in
let group_max = maximumBy (compare `on` getValue) (x:same_key) in
group_max : max_from_each_group rest
Here is my feeble attempt. There surely is a nicer way but I'm not
much of a Haskell programmer.
import Data.List
type Key = String
type Score = Int
data Thing = Thing Key Score
deriving (Show, Ord)
instance Eq Thing where
(Thing k1 _) == (Thing k2 _) = k1 == k2
(Thing k1 _) /= (Thing k2 _) = k1 /= k2
thingSort :: [Thing] -> [Thing]
thingSort = Data.List.sortBy (flip compare)
ex = [Thing "a" 7, Thing "b" 5, Thing "a" 10]
filtered = nub (thingSort ex)