how can i convert a string to tuple - string

hello we have to create a code with turns for example "1T3e1s1t" into [(1,'T'),(3,'e'),(1,'s'),(1,'t')]
here is my code
unformat :: String -> [(Int, Char)]
unformat [] = []
unformat (x:xs) = [(unformat' + 1, x)] ++ unformat xss
where
unformat' = length (takeWhile (== x)xs)
xss = drop unformat' xs
it works but the output is "1T3e" -> [(1,'1'),(1,'T'),(1,'3'),(1,'e')]
other than the takeWhile - drop function i get errors. The usage of the function replicate ive tried as well but with the wrong output again
unformat :: String -> [(Int, Char)]
unformat [] = []
unformat (x:xs) = (replicate (fst x) (snd x)) ++ unformat xs
id appreciate any kind of help sincerely

You can pattern-match also by multiple elements at the beginning of a list (like a:b:xs):
module Main where
import Data.Char
main = print $ unformat "1T3e1s1t" -- [(1,'T'),(3,'e'),(1,'s'),(1,'t')]
unformat :: String -> [(Int, Char)]
unformat (i:c:xs) = (digitToInt i, c) : unformat xs
unformat _ = []
Data.Char.digitToInt converts '0' to 0 and 'f' to 15, for example.

Here my solution with foldl. In each step we remember prev chars as a Jsut c if it's the first item of tuple or Nothing if it's second item of tuple.
module Main where
import Data.Char
main :: IO ()
main = print $ unformat "1T3e1s1t"
unformat :: String -> [(Int, Char)]
unformat s = snd $ foldl opr (Nothing , []) s
where
opr (prev, acc) c = case prev of
Just n -> (Nothing, acc ++ [(digitToInt n, c)])
Nothing -> (Just c, acc)
The output will be:
[(1,'T'),(3,'e'),(1,'s'),(1,'t')]

Related

String to List of Int

I would like to incorporate Maybe [int] into this.
The code should take a string and filter out spaces turning it into a list of integers and if their are letters return Nothing.
text2digits :: String -> [Int]
text2digits s = case s of
[] -> []
x:xs
|isDigit x -> digitToInt x :text2digits (filter (/= ' ') xs)
|otherwise -> undefined
input "1233 5687" output: [1,2,3,3,5,6,8,7]
input "a89" required output : Nothing
current output: undefined
I have tried this but it shows up a list of errors
text2digits :: String -> Maybe [Int]
text2digits s = case s of
[] -> Just []
x:xs
|isDigit x -> Just digitToInt x :text2digits (filter (/= ' ') xs)
|otherwise -> Nothing
What is wrong with the code, that you've specified for text2digits :: String -> Maybe [Int]?
The problem is in this line:
digitToInt x :text2digits (filter (/= ' ') xs)
text2digits returns value of Maybe [Int] type, but (:) expects it to be [Int].
In order to fix it, you can use fmap or <$> to apply a function to a structure inside the functor Maybe:
import Data.Char
text2digits :: String -> Maybe [Int]
text2digits s = case s of
[] -> Just []
x:xs
|isDigit x -> ((digitToInt x) :) <$> text2digits (filter (/= ' ') xs)
|otherwise -> Nothing
main = print $ text2digits "1233 5687"
Or probably you can use traverse to refactor the function a bit:
import Data.Char
text2digits :: String -> Maybe [Int]
text2digits s =
traverse digitToMaybeInt $ filter (/= ' ') s
where
digitToMaybeInt x
| isDigit x = Just $ digitToInt x
| otherwise = Nothing
main = print $ text2digits "89"

Filter by length

How I can make here filter (x:xs) = (x, length (x:xs)) that puts length when length > 1?
Currently, if input is abcaaabbb output is [('a',1),('b',1),('c',1),('a',3),('b',3)], but I'm looking for abca3b3.
My code:
import Data.List
encode :: [Char] -> [(Char, Int)]
encode s = map go (group s)
where go (x:xs) = (x, length (x:xs))
main = do
s <- getLine
print (encode s)
Last string will be putStrLn (concat (map (\(x,y) -> x : [y]) (encode s))) for convert list to string.
As I am a newbie myself, this is probably not very haskellian. But you can do it about like this (xs as would be the list [('a', 1), ('b', 2), ('a', 3)]):
Create "a1b2a3":
concat $ map (\(c, l) -> c:(show l)) xs
Filter out 1s:
filter (\x -> x /= '1') "a1b2a3"
will give you "ab2a3"
You can't have a list like this in Haskell:
[('a'),('b'),('c'),('a',3),('b',3)]
Each element if a list needs to have the same type in haskell, and ('c') [('a') :: Char] and ('b',3) [('a',1) :: Num t => (Char, t)] are different types.
Maybe also have a look at List of different types?
I would suggest, that you change your list to a (Char, Maybe num) datastructure.
Edit:
From your new question, I think you have been searching for this:
import Data.List
encode :: [Char] -> [(Char, Int)]
encode s = map go (group s)
where go (x:xs) = (x, length (x:xs))
f :: (Char, Int) -> String
f (a, b) = if b == 1 then [a] else [a] ++ show b
encode2 :: [(Char, Int)] -> String
encode2 [] = []
encode2 (x:xs) = f(x) ++ encode2 xs
main = do
s <- getLine
putStrLn $ encode2 $ encode s
Not sure if this suits your needs, but if you do not need filtering, this does the work:
encode::String -> String
encode "" = ""
encode (x:xs) = doIt0 xs x 1 where
doIt0 [] ch currentPos = [ch]++showPos currentPos
doIt0 (x:xs) ch currentPos
|x==ch = doIt0 xs ch $ currentPos+1
|otherwise= [ch]++ (showPos currentPos) ++ (doIt0 xs x 1)
showPos pos = if pos> 1 then show pos else ""
main = do
s <- getLine
print (encode s)

function that returns a list [0,[x1],[x1,x2],[x1,x2,x3]...] where [x1,x2,x3....] is the original list

How can I make in Haskell a function that gets a list and return a list of lists in this way:
[x1,x2,x3,x4,x5....]
it should return :
[[0],[x1],[x1,x2],[x1,x2,x3],[x1,x2,x3,x4][x1,x2,x3,x4,x5]....]
without using ready function that do it in Haskell.
I assume you mean the empty list [] at the start, not [0].
In which case, it's just inits.
Here's it's definition if you want to write it yourself:
inits xs = [] : case xs of [] -> []
x : xs' -> map (x :) (inits xs')
Assuming you want the empty list at the start:
prefixes :: [a] -> [[a]]
prefixes ls = map (\x -> take x ls) [0..(length ls)]
Code:
import System.IO
transform :: [Int] -> [[Int]]
transform list = trans 0
where trans n = case (length list) >= n of
True -> (take n list):( trans (n+1) )
False -> []
main = do
print . show $ transform [1..7]
Output:
$> ./transform
"[[],[1],[1,2],[1,2,3],[1,2,3,4],[1,2,3,4,5],[1,2,3,4,5,6],[1,2,3,4,5,6,7]]"
Edit: To work with Infinite Lists
transform :: [a] -> [[a]]
transform list = trans 0 []
where
trans :: a -> [a] -> [[a]]
trans n last = case last == list of
False -> [take n list]++(trans (n+1) $ take n list)
True -> []

Haskell -Changing a Char to another specified Char in a specified position in a String

I have been learning some Haskell and I came up with a solution to one of my exercise which I was trying to figure out .
Changes a Char to another specified Char in a specified position in a String
changeStr :: Int -> Char -> String -> String
changeStr x char zs = (take (x-1) zs) ++ [(changeChar (head (take x zs)) char)] ++ (drop x zs)
Changes a Char to another Char
changeChar :: Char -> Char -> Char
changeChar x y = y
I just wanted to ask is there any other way in which I could do this in a more simpler way using different methods ?
The thing that screams for generalization is changeChar. It's actually very close to a very common Haskell Prelude function called const. To get changeChar we just need to flip const.
const :: a -> b -> a
const a b = a
changeChar :: Char -> Char -> Char
changeChar = flip const
-- = flip (\a _ -> a)
-- = \_ a -> a
-- _ a = a
Beyond that, your code is fairly reasonable, but can be cleaned up by using a function splitAt
splitAt :: Int -> [a] -> ([a], [a])
splitAt n xs = (take n xs, drop n xs)
changeChar x char xs =
let (before, _it:after) = splitAt (x - 1)
in before ++ (char:after)
which also highlights a slight problem with this definition in that if your index is too large it will throw a pattern matching failure. We could fix that by making the function return an unmodified string if we "fall off the end"
changeChar x char xs =
let (before, after) = splitAt (x - 1)
in case after of
[] -> []
(_:rest) -> char:rest
There's a general pattern here as well of applying a modifying function at a particular place in a list. Here's how we can extract that.
changeAt :: Int -> (a -> a) -> [a] -> [a]
changeAt n f xs =
let (before, after) = splitAt (n-1)
in case after of
[] -> []
(x:rest) -> (f x):rest
We can use this to iterate the notion
-- | Replaces an element in a list of lists treated as a matrix.
changeMatrix :: (Int, Int) -> a -> [[a]] -> [[a]]
changeMatrix (i, j) x = changeAt i (changeAt j (const x))
What you have is pretty much what you need, except the function changeChar is just flip const, and you could rewrite yours as
changeStr x char zs = take (x-1) zs ++ [char] ++ drop x zs
If you wanted to be complicated, you could use splitAt from Data.List and the fact that fmap f (a, b) = (a, f b)
changeStr idx c str = uncurry (++) $ fmap ((c:) . tail) $ splitAt (idx - 1) str
And if you wanted to be really complicated, you could ask the pointfree bot how to write it without explicit function arguments
changeStr = ((uncurry (++) .) .) . flip ((.) . fmap . (. tail) . (:)) . splitAt . subtract 1

Haskell filter string with only the first occuring Char

I want to filter a string with a string.
What I want is to use delete every first occurring char.
myFunc :: String -> String -> String
Like:
myFunc "dddog" "bigdddddog" = "biddg"
In "dddog": 3x d, 1x o, 1x g
In the second string it removed 3x d, 1x o and 1x g
So the output: biddg
I can't use filter for it, because it will delete all occurring chars.
And I struggled a long time with it.
Thanks in advance:)
How about
Prelude> :m +Data.List
Prelude Data.List> "bigdddddog" \\ "dddog"
"biddg"
Not the nicest solution, but you can understand easier what's going on:
myfunc :: String -> String -> String
myfunc [] xs = xs
myfunc (x:xs) ys = myfunc xs $ remove x ys
where
remove _ [] = []
remove x (y:ys) = if x == y then ys else y : remove x ys
As you commented, you want to use guards. Do you mean this?
myfunc :: String -> String -> String
myfunc [] xs = xs
myfunc (x:xs) ys = myfunc xs $ remove x ys
remove :: Char -> String -> String
remove _ [] = []
remove x (y:ys)
| x == y = ys
| otherwise = y : remove x ys
some of the other solutions don't seem to produce the same result you posted. I think I have a simple solution that does what you asked for but I may be misunderstanding what you want. All I do in the following code is go though the list and apply 'delete' to every element in the list. It's not exactly efficient but it gets the job done.
import Data.List
myFunc (x:xs) ys = myFunc xs (delete x ys)
myFunc [] ys = ys
There are perhaps more efficient solutions like storing the "to remove" list in a tree with the number of occurences stored as the value then traversing the main list testing to see if the count at that key was still greater than zero. I think that would give you O(n*lg(m)) (where n is the size of the list to be removed from and m is the size of the "to remove" list) rather than O(n*m) as is the case above. This version could also be maid to be lazy I think.
edit:
Here is the tree version I was talking abut using Data.Map. It's a bit complex but should be more efficient for large lists and it is somewhat lazy
myFunc l ys = myFunc' (makeCount l) ys
where makeCount xs = foldr increment (Map.fromList []) xs
increment x a = Map.insertWith (+) x 1 a
decrement x a = Map.insertWith (flip (-)) x 1 a
getCount x a = case Map.lookup x a of
Just c -> c
Nothing -> 0
myFunc' counts (x:xs) = if (getCount x counts) > 0
then myFunc' (decrement x counts) xs
else x : myFunc' counts xs
myFunc' _ [] = []
I am not quite sure about how you want your function to behave, how about this?
import Data.List (isPrefixOf)
myFunc :: String -> String -> String
myFunc _ [] = []
myFunc y x'#(x:xs) | y `isPrefixOf` x' = drop (length y) x'
| otherwise = x : myFilter xs y
This gives the following output in GHCi:
> myFunc "dddog" "bigdddddog"
> "bigdd"
If this is not what you had in mind, please give another input/output example.
I like kaan's elegant solution. In case you meant this...here's one where the "ddd" would only be removed if matched as a whole:
import Data.List (group,isPrefixOf,delete)
f needles str = g (group needles) str where
g needles [] = []
g needles xxs#(x:xs)
| null needle' = [x] ++ g needles xs
| otherwise = let needle = head needle'
in g (delete needle needles) (drop (length needle) xxs)
where needle' = dropWhile (not . flip isPrefixOf xxs) needles
Output:
*Main> f "dddog" "bigdddddog"
"biddg"
*Main> f "dddog" "bdigdogd"
"bdidgd"
No monadic solution yet, there you go:
import Control.Monad.State
myFunc :: String -> State String String
myFunc [] = return ""
myFunc (x:xs) = get >>= f where
f [] = return (x:xs)
f (y:ys) = if y == x then put ys >> myFunc xs
else myFunc xs >>= return . (x:)
main = do
let (a,b) = runState (myFunc "bigdddddog") "dddog" in
putStr a
Using predefined functions from Data.List,
-- mapAccumL :: (acc -> x -> (acc, y)) -> acc -> [x] -> (acc, [y])
-- lookup :: (Eq a) => a -> [(a, b)] -> Maybe b
{-# LANGUAGE PatternGuards #-}
import Data.List
picks [] = [] -- http://stackoverflow.com/a/9889702/849891
picks (x:xs) = (x,xs) : [ (y,x:ys) | (y,ys) <- picks xs]
myFunc a b = concat . snd $ mapAccumL f (picks a) b
where
f acc x | Just r <- lookup x acc = (picks r,[])
f acc x = (acc,[x])
Testing:
Prelude Data.List> myFunc "dddog" "bigdddddog"
"biddg"
edit: this is of course a bit more complex than (\\). I'll let it stand as an illustration. There could be some merit to it still, as it doesn't copy the 2nd (longer?) string over and over, for each non-matching character from the 1st (shorter) string, as delete apparently does, used in (\\) = foldl (flip delete).

Resources