So basically I want to split my string with two conditions , when have a empty space or a diferent letter from the next one.
An example:
if I have this string ,"AAA ADDD DD", I want to split to this, ["AAA","A","DDD","DD"]
So I made this code:
sliceIt :: String -> [String]
sliceIt xs = words xs
But it only splits the inicial string when an empty space exists.
How can I also split when a caracter is next to a diferent one?
Can this problem be solve easier with recursion?
So you want to split by words and then group equal elements in each split. You have the functions for doing so,
import Data.List
sliceIt :: String -> [String]
sliceIt s = concatMap group $ words s
sliceItPointFree = concatMap group . words -- Point free notation. Same but cooler
split :: String -> [String]
split [] = []
split (' ':xs) = split xs
split (x:xs) = (takeWhile (== x) (x:xs)) : (split $ dropWhile (== x) (x:xs))
So this is a recursive definition where there are 2 cases:
If head is a space then ignore it.
Otherwise, take as many of the same characters as you can, then call the function on the remaining part of the string.
Related
I'm just starting out in Haskell and this is like the third thing I'm writing, so, naturally, I'm finding myself a little stumped.
I'm trying to write a bit of code that will take a string, delete the spaces, and capitalize each letter of that string.
For example, if I input "this is a test", I would like to get back something like: "thisIsATest"
import qualified Data.Char as Char
toCaps :: String -> String
toCaps [] = []
toCaps xs = filter(/=' ') xs
toCaps (_:xs) = map Char.toUpper xs
I think the method I'm using is wrong. With my code in this order, I am able to remove all the spaces using the filter function, but nothing becomes capitalize.
When I move the filter bit to the very end of the code, I am able to use the map Char.toUpper bit. When I map that function Char.toUpper, it just capitalizes everything "HISISATEST", for example.
I was trying to make use of an if function to say something similar to
if ' ' then map Char.toUpper xs else Char.toLower xs, but that didn't work out for me. I haven't utilized if in Haskell yet, and I don't think I'm doing it correctly. I also know using "xs" is wrong, but I'm not sure how to fix it.
Can anyone offer any pointers on this particular problem?
I think it might be better if you split the problem into smaller subproblems. First we can make a function that, for a given word will capitalize the first character. For camel case, we thus can implement this as:
import Data.Char(toUpper)
capWord :: String -> String
capWord "" = ""
capWord (c:cs) = toUpper c : cs
We can then use words to obtain the list of words:
toCaps :: String -> String
toCaps = go . words
where go [] = ""
go (w:ws) = concat (w : map capWord ws)
For example:
Prelude Data.Char> toCaps "this is a test"
"thisIsATest"
For Pascal case, we can make use of concatMap instead:
toCaps :: String -> String
toCaps = concatMap capWord . words
Inspired by this answer from Will Ness, here's a way to do it that avoids unnecessary Booleans and comparisons:
import qualified Data.Char as Char
toCaps :: String -> String
toCaps = flip (foldr go (const [])) id
where go ' ' acc _ = acc Char.toUpper
go x acc f = f x:acc id
Or more understandably, but perhaps slightly less efficient:
import qualified Data.Char as Char
toCaps :: String -> String
toCaps = go id
where go _ [] = []
go _ (' ':xs) = go Char.toUpper xs
go f (x :xs) = f x:go id xs
There are a number of ways of doing it, but if I were trying to keep it as close to how you've set up your example, I might do something like:
import Data.Char (toUpper)
toCaps :: String -> String
toCaps [] = [] -- base case
toCaps (' ':c:cs) = toUpper c : toCaps cs -- throws out the space and capitalizes next letter
toCaps (c:cs) = c : toCaps cs -- anything else is left as is
This is just using basic recursion, dealing with a character (element of the list) at a time, but if you wanted to use higher-order functions such as map or filter that work on the entire list, then you would probably want to compose them (the way that Willem suggested is one way) and in that case you could probably do without using recursion at all.
It should be noted that this solution is brittle in the sense that it assumes the input string does not contain leading, trailing, or multiple consecutive spaces.
Inspired by Joseph Sible 's answer, a coroutines solution:
import Data.Char
toCamelCase :: String -> String
toCamelCase [] = []
toCamelCase (' ': xs) = toPascalCase xs
toCamelCase (x : xs) = x : toCamelCase xs
toPascalCase :: String -> String
toPascalCase [] = []
toPascalCase (' ': xs) = toPascalCase xs
toPascalCase (x : xs) = toUpper x : toCamelCase xs
Be careful to not start the input string with a space, or you'll get the first word capitalized as well.
I am very new to Haskell. I am trying to return a list of strings from a given string (which could contain non-letter characters) but I get a single string in the list.
The below code shows What I have tried so far:
toLowerStr xs = map toLower xs
--drop non-letters characters
dropNonLetters xs = words $ (filter (\x -> x `elem` ['a'..'z'])) $ toLowerStr xs
lowercase all the characters by using toLower function
remove non-letter characters by using filter function
return a list of strings by using words function
I think the filter function is removing the white spaces and therefore it becomes a single string. I tried using isSpace function but I don't know exactly how to implement it in this case.
What is it that I am doing wrong? I get this output:
λ> dropNonLetters "ORANGE, apple! APPLE!!"
["orangeappleapple"]
But I want to achieve the below output:
λ> dropNonLetters "ORANGE, apple! APPLE!!"
["orange","apple","apple"]
I think the filter function is removing the white spaces and therefore it becomes a single string.
That is correct. As filter predicate you write \x -> x `elem` ['a'..'z']. ['a'..'z'] is a list that contains lowercase letters, so for whitespace, the predicate will fail, and thus you should allow spaces as well.
We can for instance add the space character to the list:
dropNonLetters xs = words $ (filter (\x -> x `elem` (' ':['a'..'z'])))) $ toLowerStr xs
But this is inelegant and does not really explain itself. The Data.Char module however ships with two functions that are interesting here: isLower :: Char -> Bool, and isSpace :: Char -> Bool. We can use this like:
dropNonLetters xs = words $ (filter (\x -> isLower x || isSpace x)) $ toLowerStr xs
isLower and isSpace are not only more "descriptive" and elegant. Usually these functions will be faster than a membership check (which will usually be done in O(n)), and furthermore it will also take into account tabs, new lines, etc.
We can also perform an eta-reduction on the function:
dropNonLetters = words . (filter (\x -> isLower x || isSpace x)) . toLowerStr
This then produces:
Prelude Data.Char> dropNonLetters "ORANGE, apple! APPLE!!"
["orange","apple","apple"]
I advise you to rename the function dropNonLetters, since now it does not fully explain that it will generate a list of words. Based on the name, I would think that it only drops non-letters, not that it converts the string to lowercase nor that it constructs words.
here's an example of separating characters into separate string lists:
sortNumbers :: [Char] -> [String]
sortNumbers args = filter (\strings ->strings/= "") $ zipWith (\x numbers -> filter (\char -> char == numbers) x) (repeat args)
['1'..'9']
I want to split a String in Haskell.
My inicial String would look something like
["Split a String in Haskell"]
and my expected output would be:
["Split","a","String","in","Haskell"].
From what i've seen, words and lines don't work here, because i have the type [String] instead of just String.
I've tried Data.List.Split, but no luck there either.
import Data.List
split = (>>= words)
main = print $ split ["Split a String in Haskell"]
map words makes [["Split","a","String","in","Haskell"]] from ["Split a String in Haskell"], and concat makes [x] from [[x]]. And concat (map f xs) is equal to xs >>= f. And h xs = xs >>= f is equal to h = (>>= f).
Another way, more simple would be
split = words . head
How do I remove the first space of a string in Haskell?
For example:
removeSpace " hello" = "hello"
removeSpace " hello" = " hello"
removeSpace "hello" = "hello"
Here are multiple remove-space options, to show of a few functions and ways of doing things.
To take multiple spaces, you can do
removeSpaces = dropWhile (==' ')
This means the same as removeSpaces xs = dropWhile (==' ') xs, but uses partial application (and so does (==' ') in essence).
or for more general removal,
import Data.Char
removeWhitespace = dropWhile isSpace
If you're really sure you just want to take one space (and you certainly seem to be), then pattern matching is clearest:
removeASpace (' ':xs) = xs -- if it starts with a space, miss that out.
removeASpace xs = xs -- otherwise just leave the string alone
This works because in haskell, String = [Char] and (x:xs) means the list that starts with x and carries on with the list xs.
To remove one whitespace character, we can use function guards (if statements with very light syntax, if you've not met them):
removeAWhitespace "" = "" -- base case of empty string
removeAWhitespace (x:xs) | isSpace x = xs -- if it's whitespace, omit it
| otherwise = x:xs -- if it's not keep it.
Simply use pattern matching:
removeSpace (' ':xs) = xs
removeSpace xs = xs
In Haskell, strings are simply list of characters, i.e., the Prelude defines
type String = [Char]
Furthermore, there are about three ways to write a function:
Completely roll it yourself using the two most fundamental tools you have at your disposal: pattern matching and recursion;
Cleverly combine some already written functions; and, of course
A mix of these.
If you are new to Haskell and to functional programming, I recommend writing most of your functions using the first method and then gradually shift toward using more and more predefined functions.
For your problem—removing the first space character (' ') in a string—pattern matching and recursion actually make a lot of sense. As said, strings are just lists of characters, so we will end up with nothing but a simple list traversal.
Let us first write a signature for your function:
removeSpace :: [Char] -> [Char]
(I have written [Char] rather than String to make it explicit that we are performing a list traversal here.)
Pattern matching against a list, we need to consider two cases: the list being empty ([]) and the list consisting of a head element followed by a tail (c : cs).
Dealing with the empty list is, as always, simple: there are no characters left, so there is nothing to remove anymore and we simply return the empty list.
removeSpace [] = []
Then the situation in which we have a head element (a character) and a tail list. Here we need to distinguish two cases again: the case in which the head character is a space and the case in which it is any other character.
If the head character is a space, it will be the first space that we encounter and we need to remove it. As we only have to remove the first space, we can return the remainder of the list (i.e., the tail) without further processing:
removeSpace (' ' : cs) = cs
What remains is to deal with the case in which the head character is not a space. Then we need to keep it in the returned list and, moreover, we need to keep seeking for the first space in the remainder of the list; that is, we need to recursively apply our function to the tail:
removeSpace (c : cs) = c : removeSpace cs
And that's all. The complete definition of our function now reads
removeSpace :: [Char] -> [Char]
removeSpace [] = []
removeSpace (' ' : cs) = cs
removeSpace (c : cs) = c : removeSpace cs
This is arguably as clear and concise a definition as any clever combining of predefined functions would have given you.
To wrap up, let us test our function:
> removeSpace " hello"
"hello"
> removeSpace " hello"
" hello"
> removeSpace "hello"
"hello"
If you really want construct your function out of predefined functions, here is one alternative definition of removeSpace that will do the trick:
removeSpace :: [Char] -> [Char]
removeSpace = uncurry (flip (flip (++) . drop 1)) . break (== ' ')
(You can see why I prefer the one using explicit pattern matching and recursion. ;-))
Note: I have assumed that your objective is indeed to remove the first space in a string, no matter where that first space appears. In the examples you have given, the first space is always the first character in the string. If that's always the case, i.e., if you are only after dropping a leading space, you can leave out the recursion and simply write
removeSpace :: [Char] -> [Char]
removeSpace [] = []
removeSpace (' ' : cs) = cs
removeSpace (c : cs) = c : cs
or, combining the first and last cases,
removeSpace :: [Char] -> [Char]
removeSpace (' ' : cs) = cs
removeSpace cs = cs
or, using predefined functions,
removeSpace :: [Char] -> [Char]
removeSpace = uncurry ((++) . drop 1) . span (== ' ')
To remove the first space anywhere in a string:
removeSpace :: String -> String
removeSpace = (\(xs,ys) -> xs ++ drop 1 ys) . span (/=' ')
Where span grabs characters until it finds a space or reaches the end of the string.
It then splits the results and puts them in a tuple that we take and combine, skipping the first character in the second list (the space). Additionally we assert that the remainder is not null (an empty list) - if it is, we can't get the tail as an empty list can't have a tail can it? So if it is, we just return an empty list.
I'm learning haskell. I'm reading a string from a text file and need to make this string becomes a list of char.
The input file is this:
Individuo A; TACGATCAAAGCT
Individuo B; AATCGCAT
Individuo C; TAAATCCGATCAAAGAGAGGACTTA
I need convert this string
S1 = "AAACCGGTTAAACCCGGGG" in S1 =
["A","A","A","C","C","G","G","T","T","A","A","A","C","C","C","G","G","G","G"]
or S1 =
['A','A','A','C','C','G','G','T','T','A','A','A','C','C','C','G','G','G','G']
but they are separated by ";"
What should I do?
What can I do?
after getting two lists, I send them to this code:
lcsList :: Eq a => [a] -> [a] -> [a]
lcsList [] _ = []
lcsList _ [] = []
lcsList (x:xs) (y:ys) = if x == y
then x : lcsList xs ys
else
let lcs1 = lcsList (x:xs) ys
lcs2 = lcsList xs (y:ys)
in if (length lcs1) > (length lcs2)
then lcs1
else lcs2
A rough and ready way to split out each of those strings is with something like this - which you can try in ghci
let a = "Individuo A; TACGATCAAAGCT"
tail $ dropWhile (/= ' ') $ dropWhile (/= ';') a
which gives you:
"TACGATCAAAGCT"
And since a String is just a list of Char, this is the same as:
['T', 'A', 'C', 'G', ...
If your file consists of several lines, it is quite simple: you just need to skip everything until you find “;”. If your file consists of just one line, you’ll have to look for sequences’ beginnings and endings separately (hint: sequence ends with space). Write a recursive function to do the task, and use functions takeWhile, dropWhile.
A String is already a list of Char (it is even defined like this: type String = [Char]), so you don’t have to do anything else. If you need a list of Strings, where every String consists of just one char, then use map to wrap every char (once again, every String is a list, so you are allowed to use map on these). To wrap a char, there are three alternatives:
Use lambda function: map (\c -> [c]) s
Use operator section: map (:[]) s
Define a new function: wrap x = [x]
Good luck!