List of ints to string - haskell? - haskell
I am trying to take a list of integers and repeat them a number of times, but as a string in haskell. The expected output is:
> nnn [3,1,5] = ["3-3-3","1","5-5-5-5-5"]
> nnn [10,2,4] = ["10-10-10-10-10-10-10-10-10-10","2-2","4-4-4-4"]
Now I think I am close... But I can't quite turn a list of ints into a String, and definitely don't know what to do about the hyphen. Here's my code so far, and output:
nnn :: [Int] -> [[Char]]
nnn list = map show (map (\x -> take x $ repeat x) list)
And it gives me:
> nnn [3,1,5] = ["[3,3,3]","[1]","[5,5,5,5,5]"]
(I'm close at least!) Can anyone point me in the right direction to look here? :)
A separate function to repeat a number into a hyphen-separated string seems useful here. Convert the number to a string first, replicate it, and use intercalate to insert a hyphen between each element and join them:
repeatNumber :: Int -> String
repeatNumber n = intercalate "-" $ replicate n $ show n
Then nnn is nice and simple:
nnn :: [Int] -> [String]
nnn = map repeatNumber
(replicate a b being take a $ repeat b)
Related
Removing specific elements from lists in Haskell
I'm having a hard time getting Haskell and functional programming together in my head. What I am trying to do is manipulate a string so that I am printing/returning specific characters each time based on a number given. For example: printing "testing" 2 = "etn" printing "testing" 3 = "sn" I've read a lot online, and from what I understand I can achieve this with filtering and cycling, but I cannot get/understand the syntax of this language to get a working program.
I'll try to describe my thought process so you can follow. This function fits the pattern of creating an output list (here a string) from an input seed (here a string) by repeated function application (here dropping some elements). Thus I choose an implementation with Data.List.unfoldr. unfoldr :: (b -> Maybe (a, b)) -> b -> [a] Okay so, I need to turn the seed b into (Maybe) an output a and the rest of the string. I'll call this subfunction f and pass it into unfoldr. printing s n = unfoldr f s where f b = case drop n b of [] -> Nothing (x:xs) -> Just (x,xs) It turns out that attempting to take the head off the front of the list and returning a Maybe is also a common pattern. It's Data.List.uncons, so printing s n = unfoldr (uncons . drop n) s Very smooth! So I test it out, and the output is wrong! Your specified output actually eg. for n=2 selects every 2nd character, ie. drops (n-1) characters. printing s n = unfoldr (uncons . drop (n-1)) s I test it again and it matches the desired output. Phew!
To demonstrate the Haskell language some alternative solutions to the accepted answer. Using list comprehension: printing :: Int -> String -> String printing j ls = [s | (i, s) <- zip [1 .. ] ls, mod i j == 0] Using recursion: printing' :: Int -> String -> String printing' n ls | null ls' = [] | otherwise = x : printing' n xs where ls' = drop (n - 1) ls (x : xs) = ls' In both cases I flipped the arguments so it is easier to do partial application: printing 5 for example is a new function and will give each 5th character when applied to a string. Note with a minor modification they will work for any list takeEvery :: Int -> [a] -> [a]
Haskell converting string to binary number
I need to convert a string of chars to a list of binary numbers in Haskell. I've written two functions to do this, but I'm not sure how to combine them into one. So far I have dec[]=[] dec(x:xs) = ord(x): dec xs to convert every char in the list into a decimal number. The next function bin 0 = [0] bin n| n `mod` 2 == 1 = bin (n `div` 2) ++ [1] | n `mod` 2 == 0 = bin (n `div` 2) ++ [0] converts a decimal number to its binary equivalent. I'm not sure how to apply the second function to every element in the list, in order to convert every char to its equivalent in binary. I tried to use the where clause: where n = dec(x:xs) = ord(x): dec xs but this is not valid as there are two equals signs on the same line. How can I achieve the correct functionality?
You can be pretty certain that an Int will be stored in binary. It only appears to be in decimal because it is converted to decimal when you print it. So, the name dec is a misnomer, that function is converting a String into a sequence of numbers that represent the Unicode value of each character. You can avoid explicit recursion by using map: toUnicode :: String -> [Int] toUnicode = map ord Note that this function uses so-called point-free style. The expected argument is missing, but will be passed to map when supplied by the caller. The Bin function will not compile because it starts with an upper case character, making it a data constructor. You should name the function starting with a lower case character. According to your example output, you want leading zeros in your binary representations, so you can't stop conversion when the value becomes zero. You need to continue until you have converted the desired number of digits, which appears to be 8. It is also inefficient to keep appending to a list. It is better to prepend, and then reverse the result. toBinary :: Int -> [Int] toBinary = go 8 [] where go 0 acc _ = reverse acc go n acc x = go (n-1) (bit:acc) x' where (x', bit) = x `divMod` 2 Here, we use a helper function, go which counts down the number of remaining digits as it builds up the list of 1's and 0's. So, now we have a function to convert a String into a list of Ints, and a function to convert an Int into a list of 0/1 Ints, and we want to glue them together to make a function that converts a String to a list of 0/1 Ints. If we map our toBinary function over the result of toUnicode, we will get a list of lists, which must be concatenated to form a single list. This is such a common pattern that there's a function for that called, concatMap: stringToBinary :: String -> [Int] stringToBinary = concatMap toBinary . toUnicode Here we use function composition to first apply toUnicode to the String, and then concatMap the toBinary over the result.
What we want is a function of type String -> String (decimal -> binary). What you have now is dec :: String -> [Int] bin :: Int -> [Int] -- use *lowercase* So it seems impossible to compose a function of type String -> String only with these two. Besides, ord is not what you want. *Main> dec "123" [49,50,51] *Main> bin 123 [0,1,1,1,1,0,1,1] From what you have now, the possible solution would be: *Main Data.Char> toBinary = map intToDigit . bin . read *Main Data.Char> toBinary "123" "01111011" I guess your intention may be dec :: String -> Int, then bin . dec :: String -> [Int]. You can follow the type signature and retry.
Project Euler 8 - I don't understand it
I looked up for a solution in Haskell for the 8th Euler problem, but I don't quite understand it. import Data.List import Data.Char euler_8 = do str <- readFile "number.txt" print . maximum . map product . foldr (zipWith (:)) (repeat []) . take 13 . tails . map (fromIntegral . digitToInt) . concat . lines $ str Here is the link for the solution and here you can find the task. Could anyone explain me the solution one by one?
Reading the data readFile reads the file "number.txt". If we put a small 16 digit number in a file called number.txt 7316 9698 8586 1254 Runing euler_8 = do str <- readFile "number.txt" print $ str Results in "7316\n9698\n8586\n1254" This string has extra newline characters in it. To remove them, the author splits the string into lines. euler_8 = do str <- readFile "number.txt" print . lines $ str The result no longer has any '\n' characters, but is a list of strings. ["7316","9698","8586","1254"] To turn this into a single string, the strings are concatenated together. euler_8 = do str <- readFile "number.txt" print . concat . lines $ str The concatenated string is a list of characters instead of a list of numbers "7316969885861254" Each character is converted into an Int by digitToInt then converted into an Integer by fromInteger. On 32 bit hardware using a full-sized Integer is important since the product of 13 digits could be larger than 2^31-1. This conversion is mapped onto each item in the list. euler_8 = do str <- readFile "number.txt" print . map (fromIntegral . digitToInt) . concat . lines $ str The resulting list is full of Integers. [7,3,1,6,9,6,9,8,8,5,8,6,1,2,5,4] Subsequences The author's next goal is to find all of the 13 digit runs in this list of integers. tails returns all of the sublists of a list, starting at any position and running till the end of the list. euler_8 = do str <- readFile "number.txt" print . tails . map (fromIntegral . digitToInt) . concat . lines $ str This results in 17 lists for our 16 digit example. (I've added formatting) [ [7,3,1,6,9,6,9,8,8,5,8,6,1,2,5,4], [3,1,6,9,6,9,8,8,5,8,6,1,2,5,4], [1,6,9,6,9,8,8,5,8,6,1,2,5,4], [6,9,6,9,8,8,5,8,6,1,2,5,4], [9,6,9,8,8,5,8,6,1,2,5,4], [6,9,8,8,5,8,6,1,2,5,4], [9,8,8,5,8,6,1,2,5,4], [8,8,5,8,6,1,2,5,4], [8,5,8,6,1,2,5,4], [5,8,6,1,2,5,4], [8,6,1,2,5,4], [6,1,2,5,4], [1,2,5,4], [2,5,4], [5,4], [4], [] ] The author is going to pull a trick where we rearrange these lists to read off 13 digit long sub lists. If we look at these lists left-aligned instead of right-aligned we can see the sub sequences running down each column. [ [7,3,1,6,9,6,9,8,8,5,8,6,1,2,5,4], [3,1,6,9,6,9,8,8,5,8,6,1,2,5,4], [1,6,9,6,9,8,8,5,8,6,1,2,5,4], [6,9,6,9,8,8,5,8,6,1,2,5,4], [9,6,9,8,8,5,8,6,1,2,5,4], [6,9,8,8,5,8,6,1,2,5,4], [9,8,8,5,8,6,1,2,5,4], [8,8,5,8,6,1,2,5,4], [8,5,8,6,1,2,5,4], [5,8,6,1,2,5,4], [8,6,1,2,5,4], [6,1,2,5,4], [1,2,5,4], [2,5,4], [5,4], [4], [] ] We only want these columns to be 13 digits long, so we only want to take the first 13 rows. [ [7,3,1,6,9,6,9,8,8,5,8,6,1,2,5,4], [3,1,6,9,6,9,8,8,5,8,6,1,2,5,4], [1,6,9,6,9,8,8,5,8,6,1,2,5,4], [6,9,6,9,8,8,5,8,6,1,2,5,4], [9,6,9,8,8,5,8,6,1,2,5,4], [6,9,8,8,5,8,6,1,2,5,4], [9,8,8,5,8,6,1,2,5,4], [8,8,5,8,6,1,2,5,4], [8,5,8,6,1,2,5,4], [5,8,6,1,2,5,4], [8,6,1,2,5,4], [6,1,2,5,4], [1,2,5,4] ] foldr (zipWith (:)) (repeat []) transposes a list of lists (explaining it belongs to perhaps another question). It discards the parts of the rows longer than the shortest row. euler_8 = do str <- readFile "number.txt" print . foldr (zipWith (:)) (repeat []) . take 13 . tails . map (fromIntegral . digitToInt) . concat . lines $ str We are now reading the sub-sequences across the lists as usual [ [7,3,1,6,9,6,9,8,8,5,8,6,1], [3,1,6,9,6,9,8,8,5,8,6,1,2], [1,6,9,6,9,8,8,5,8,6,1,2,5], [6,9,6,9,8,8,5,8,6,1,2,5,4] ] The problem We find the product of each of the sub-sequences by mapping product on to them. euler_8 = do str <- readFile "number.txt" print . map product . foldr (zipWith (:)) (repeat []) . take 13 . tails . map (fromIntegral . digitToInt) . concat . lines $ str This reduces the lists to a single number each [940584960,268738560,447897600,1791590400] From which we must find the maximum. euler_8 = do str <- readFile "number.txt" print . maximum . map product . foldr (zipWith (:)) (repeat []) . take 13 . tails . map (fromIntegral . digitToInt) . concat . lines $ str The answer is 1791590400
If you're not familiar with the functions used, the first thing you should do is examine the types of each function. Since this is function composition, you apply from inside out (i.e. operations occur right to left, bottom to top when reading). We can walk through this line by line. Starting from the last line, we'll first examine the types. :t str str :: String -- This is your input :t lines lines :: String -> [String] -- Turn a string into an array of strings splitting on new line :t concat concat :: [[a]] -> [a] -- Merge a list of lists into a single list (hint: type String = [Char]) Since type String = [Char] (so [String] is equivalent to [[Char]]), this line is converting the multi-line number into a single array of number characters. More precisely, it first creates an array of strings based on the full string. That is, one string per new line. It then merges all of these lines (now containing only number characters) into a single array of characters (or a single String). The next line takes this new String as input. Again, let's observe the types: :t digitToInt digitToInt :: Char -> Int -- Convert a digit char to an int :t fromIntegral fromIntegral :: (Num b, Integral a) => a -> b -- Convert integral to num type :t map map :: (a -> b) -> [a] -> [b] -- Perform a function on each element of the array :t tails tails :: [a] -> [[a]] -- Returns all final segments of input (see: http://hackage.haskell.org/package/base-4.8.0.0/docs/Data-List.html#v:tails) :t take take :: Int -> [a] -> [a] -- Return the first n values of the list If we apply these operations to our string current input, the first thing that happens is we map the composed function of (fromIntegral . digitToInt) over each character in our string. What this does is turn our string of digits into a list of number types. EDIT As pointed out below in the comments, the fromIntegral in this example is to prevent overflow on 32-bit integer types. Now that we have converted our string into actual numeric types, we start by running tails on this result. Since (by the problem statement) all values must be adjacent and we know that all of the integers are non-negative (by virtue of being places of a larger number), we take only the first 13 elements since we want to ensure our multiplication is groupings of 13 consecutive elements. How this works is difficult to understand without considering the next line. So, let's do a quick experiment. After converting our string into numeric types, we now have a big list of lists. This is actually kind of hard to think about what we actually have here. For sake of understanding, the contents of the list are not very important. What is important is its size. So let's take a look at an artificial example: (map length . take 13 . tails) [1..1000] [1000,999,998,997,996,995,994,993,992,991,990,989,988] You can see what we have here is a big list of 13 elements. Each element is a list of size 1000 (i.e. the full dataset) down to 988 in descending order. So this is what we currently have for input into the next line which is, arguably, the most difficult-- yet most important-- line to understand. Why understanding this is important should become clear as we walk through the next line. :t foldr foldr :: (a -> b -> b) -> b -> [a] -> b -- Combine values into a single value :t zipWith zipWith :: (a -> b -> c) -> [a] -> [b] -> [c] -- Generalization of zip :t (:) (:) :: a -> [a] -> [a] -- Cons operator. Add element to list :t repeat repeat :: a -> [a] -- Infinite list containing specified value Remember how I mentioned we had a list of 13 elements before (of varying-sized lists)? This is important now. The line is going to iterate over that list and apply (zipWith (:)) to it. The (repeat []) is such that each time zipWith is called on a subsequence, it starts with an empty list as its base. This allows us to construct a list of lists containing our adjacent subsequences of length 13. Finally, we get to the last line which is pretty easy. That said, we should still be mindful of our types :t product product :: Num a => [a] -> a -- Multiply all elements of a list together and return result :t maximum maximum :: Ord a => [a] -> a -- Return maximum element in the list The first thing we do is map the product function over each subsequence. When this has completed we end up with a list of numeric types (hey, we finally don't have a list of lists anymore!). These values are the products of each subsequence. Finally, we apply the maximum function which returns only the largest element in the list.
EDIT: I found out later what the foldr expression was for. (See comments bellow my answer). I think that this could be expressed in different way - You can simply add a guard at the end of the list. My verbose version of that solution would be: import Data.List import Data.Char euler_8 = do let len = 13 let str1 = "123456789\n123456789" -- Join lines let str2 = concat (lines str1) -- Transform the list of characters into a list of numbers let lst1 = map (fromIntegral . digitToInt) str2 -- EDIT: Add a guard at the end of list let lst2 = lst1 ++ [-1] -- Get all tails of the list of digits let lst3 = tails lst2 -- Get first 13 digits from each tail let lst4 = map (take len) lst3 -- Get a list of products let prod = map product lst4 -- Find max product let m = maximum prod print m
How to input several values in one line in haskell
For example, I want to write a program which will take 3 integers as input from command line. The functions I have learned is readLn to read values from entire line. But readLn seems to parse the entire line as a single value. How can I get the three values of one line with haskell?
Read a line with getLine, split it into words, and read each: readInts :: IO [Int] readInts = fmap (map read.words) getLine it reads any number of Ints: ghci> readInts 1 2 3 [1,2,3] ghci> readInts 1 2 3 4 5 6 [1,2,3,4,5,6] You could restrict to three: read3Ints :: IO [Int] read3Ints = do ints <- readInts if length ints == 3 then return ints else do putStrLn ("sorry, could you give me exactly three integers, " ++ "separated by spaces?") read3Ints which looks like this: ghci> read3Ints 1 2 sorry, could you give me exactly three integers, separated by spaces? 1 23 , 5, 6 sorry, could you give me exactly three integers, separated by spaces? 1,2,3 sorry, could you give me exactly three integers, separated by spaces? 1 3 6 The secrets of fmap fmap works a bit like map, but you can use it more widely: ghci> fmap (*10) [1,2,3,4] [10,20,30,40] ghci> fmap (*10) (Just 5) Just 50 ghci> map (fmap (*10)) [Left 'b', Right 4, Left 'c', Right 7] [Left 'b',Right 40,Left 'c',Right 70] ghci> fmap words getLine Hello there me hearties! ["Hello","there","me","hearties!"] In getInts, I did fmap (map read.words) to split the line by spaces, then map read to turn each one into an Int. The compiler knows I wanted Int because of the type signature - I'd get an error if I omitted it.
There several ways you could go about this, but I'd prefer the one using reads. This function has type Read a => ReadS a, where ReadS a is just a type alias for String -> [(a, String)]. It pulls characters from the provided string, stopping when it no longer successfully parses, then returns a list containing a tuple of the parsed value and the remaining string. It uses a list for a more flexible definition, but in practice you'll never see it return a list more than 1 element. An example would be > reads "1 2 3" :: [(Int, String)] [(1, " 2 3")] > reads " 2 3" :: [(Int, String)] [(2, " 3")] Using this function, we can parse a line for Ints and it'll automatically stop when it fails to parse one or the string is empty. We just need a way to chain together multiple calls. Ideally, we'd like a function with the type (s -> [(a, s)]) -> s -> [a] so that we can re-use it: chain :: (s -> [(a, s)]) -> s -> [a] chain f s = case f s of [] -> [] [(a, newS)] -> a : chain f newS xs -> map fst xs ++ chain f (last $ map snd xs) Then you can use it as > chain reads "1 2 3" :: [Int] [1, 2, 3] > chain reads "1 2 3 asdf" :: [Int] [1, 2, 3] > chain reads "asdf 1 2 3" :: [Int] [] Then you just have to do read3Ints :: String -> [Int] read3Ints = take 3 . chain reads
What about: getInts::[Int] getInts = do s<-getLine map read . words $ s
String letter percentages in Haskell
I'm trying to write a Haskell function that will take a String say "PLATYPUS" and will return the relative percentages of Characters in that word i.e. characterPercentages "PLATYPUS" would return: [(P,25),(A,13),(L,13),(S,13),(T,13),(U,13),(Y,13)]. I know I can use tuples, but after that I'm a bit stumped?
First, you need to understand what are you going to get. As I understand, you wish to have type String = [Char] --already in Prelude String -> [(Char,Int)] "PLATYPUS" -=> [('P',2),('A',1),('L',1),('S',1),('T',1),('U',1),('Y',1)] You could combine group grouping lists from Data-List with mapping using length function String -> [[Char]] [[Char]] -> [(Char,Int)] UPDATED If we talk about first part - count letters, we can do next: > :m Data.List > map (\c -> (head c, length c)) $ group $ sort "PLATYPUSAAA" [('A',4),('L',1),('P',2),('S',1),('T',1),('U',1),('Y',1)] So, let's found relative numbers, we change length c to 100*(length c) 'div' ls: > let frqLetters s = let ls = length s in map (\c -> (head c, 100 * (length c) `div` ls)) $ group $ sort s > frqLetters "PLATYPUSAAA" [('A',36),('L',9),('P',18),('S',9),('T',9),('U',9),('Y',9)]