Haskell -- How to draw lists of characters from a string? - haskell

How to draw lists of characters from a string?
For example, for a string "abcdefghi", return three strings "adg" "deh" "cfi".
for the first string, it's the 1st, n+1th and n+2th characters from the original string, n is the number of strings to generate.

Two solutions:
First: cryptic and short
drawlist :: Int -> String -> [String]
drawlist n s = [map fst $ filter snd $ zip str [mod c n == i | c<-[0..] ] | i <- [0..(n-1)]]
Second: long and maybe clearer
initlist :: Int -> [String]
initlist 0 = []
initlist n = "":(initlist (n-1))
addtonth :: [String] -> Int -> Char -> [String]
addtonth (x:xc) 1 c = (x++[c]):(addtonth xc 0 c)
addtonth (x:xc) i c = x:(addtonth xc (i-1) c)
addtonth [] i c = []
drawlist' :: Int -> String -> Int -> [String] -> [String]
drawlist' n (x:xs) i s = drawlist' n xs (mod (i+1) n) $ addtonth s (i+1) x
drawlist' n [] i s = s
drawlist :: Int -> String -> [String]
drawlist n s = drawlist n s 0 $ initlist n
Test:
Prelude> str = "abcdefghi"
Prelude> drawlist 2 str
["acegi","bdfh"]
Prelude> drawlist 3 str
["adg","beh","cfi"]
Prelude> drawlist 4 str
["aei","bf","cg","dh"]
Prelude> drawlist 5 str
["af","bg","ch","di","e"]

Related

Output of a list of Maybe Int with Just in every element in Haskell

I have this function which takes an integer n and returns a list of type Maybe Int, containing the unique prime factors. I don't understand why it returns them with Just inside every element of the list.
I expect an output like this:
primeFactors 75 = Just [3,5]
But I have one that looks like this:
primeFactor 75 = [Just 5,Just 3,Just 1]
Here is my code:
divides :: Int -> Int -> Bool
divides m n = rem m n == 0
transform :: Int -> Int
transform n = (n*2) + 1
isComposite :: Int -> Bool
isComposite n = foldl (||) (divides n 2) (map (divides n) (map (transform) [1..(div n 4)]))
isPrime :: Int -> Bool
isPrime n
| n <= 0 = error "Makes no sense"
| n < 4 = True
| otherwise = not (isComposite n)
primeFactors :: Int -> [Maybe Int]
primeFactors 0 = [Nothing]
primeFactors n = primeFactors2 n ((div n 2)+1)
primeFactors2 :: Int -> Int -> [Maybe Int]
primeFactors2 n 0 = []
primeFactors2 n x
| divides n x && isPrime x = Just x:primeFactors2 n (x-1)
| otherwise = primeFactors2 n (x-1)
Here is a version of your code that I think will do what you want:
primeFactors :: Int -> Maybe [Int]
primeFactors n
| n <= 0 = Nothing
| otherwise = Just $ primeFactors2 n n
primeFactors2 :: Int -> Int -> [Int]
primeFactors2 n p
| n <= 1 || p <= 1 = []
| divides n p && isPrime p = p : primeFactors2 (n `div` p) p
| otherwise = primeFactors2 n (p-1)
isPrime :: Int -> Bool
isPrime n
| n <= 1 = False
| otherwise = not (isComposite n)
isComposite :: Int -> Bool
isComposite n =
any (divides n) [2..n-1]
divides :: Int -> Int -> Bool
divides m n =
rem m n == 0
Please note that (for clarity's sake I hope) I did remove some of your optimizations and made a major change: this one will report Just [2,2] as prime-factors for 4
(IMO you want product <$> primeFactors n == Just n).
If not (as your example indicates) it shouldn't be too hard to fix this (just take your version).
Anyway the only really interesting contribution is how primeFactor handles primeFactors2 to get you the Maybe result.

Concatenate to a list of string another string

The below code gives back a list of String but I want it work on multiple cases. The problem is that I can't create the same exact result with recursion.
The program gives back the following result:
replaceTabs 6 ["\thello world"]
=> [" hello world"]
Now this should work with a longer list like:
replaceTabs 6 ["asd dsa","\thello world"]
=> ["asd dsa"," hello world"]
Simple concat doesn't work, because it will give back undefined pattern.
replaceTab' :: Int -> [[Char]] -> [Char]
replaceTab' n [[x]] =
if x == '\t' then replicate n ' '
else [x]
replaceTabs :: Int -> [String]-> [String]
replaceTabs n [""] = [""]
replaceTabs n (x:xs) = (return . concat $ [replaceTab' n [a] | a <- (map (:[]) (x))])
This
replaceTab' :: Int -> [[Char]] -> [Char]
is the same as,
replaceTab' :: Int -> [String] -> String
What you should focus on is implementing a function,
replaceTab :: Int -> String -> String
which "fixes" a single String. Then replaceTabs is simply,
replaceTabs :: Int -> [String] -> [String]
replaceTabs n = map (replaceTab n)

Haskell Recursion with Chars

Write a recursive Haskell function
makeString :: Int -> Char -> Char -> String
such that makeString n ch1 ch2 returns a string as follows:
When n is positive, the string has length 3n-2 and contains n copies
of ch1, each copy separated by two copies of ch2.
When n is less than or equal to zero, the string is the empty string.
For example, the function has the following behavior:
Main > makeString 5 'a' '!'
"a!!a!!a!!a!!a"
Main > makeString 1 'a' '!'
"a"
Main > makeString 10 '6' '#'
"6##6##6##6##6##6##6##6##6##6"
So far I have:
makeString :: Int -> Char -> Char -> String
makeString n ch1 ch2
|n <= 0 = [ ]
|otherwise = ch1: makeString(3*n-2)(ch2)(ch1)
Main> makeString 5 'a' '!'
"a!a!a!a!a!a!a!a!a!a!a!a!a!a!a!a!a!a!a!a"
A quick and dirty implementation
module Test where
merge :: [a] -> [a] -> [a]
merge xs [] = xs
merge [] ys = ys
merge (x:xs) (y:ys) = x : y : y : merge xs ys
makeString :: Int -> Char -> Char -> String
makeString 0 _ _ = []
makeString n ch1 ch2 = take ((3 * n) - 2) $ merge (replicate (3 * n) ch1) (replicate (3 * n) ch2)
The replicate creates long enough lists for merge to do its work. Works for all positive ns
Here is my solution:
makeString :: Int -> Char -> Char -> String
makeString n ch1 ch2
| n <= 0 = ""
| n == 1 = [ch1]
| otherwise = [ch1, ch2, ch2] ++ makeString (n-1) ch1 ch2

Haskell - error in find/replace function

i'm making a function that takes three string values w1, w2 and s, and returns s but with all occurrences of the string w1 replaced by w2.
i have finished it, but there is an error. if w1 is only in the string s once, it works fine. but if it occurs multiple times, it doesn't work. eg:
Main> swapwords "turtles" "goats" "more turtles are becoming blind"
"more goats are becoming blind"
swapwords "turtles" "goats" "the blue turtles, dislike the green turtles"
"the blue turtles, dislike the green goats"
here is the current code:
split :: String -> Char -> String -> [String]
split "" _ "" = []
split "" _ r = [r]
split (x:xs) c ""
| x == c = [[c]] ++ split xs c ""
| otherwise = split xs c [x]
split (x:xs) c r
| x == c = r : [[c]] ++ split xs c ""
| otherwise = split xs c (r ++ [x])
swap :: String -> String -> [String] -> [String]
swap a b [] = []
swap a b (x:xs)
|x==a = [b] ++ xs
|x/=a = [x] ++ swap a b (xs)
join :: [String] -> String
join [] = ""
join (x:xs) = x ++ join (xs)
swapwords :: String -> String -> String -> String
swapwords a b "" = []
swapwords a b c = join (swap a b d)
where d = split c ' ' []
if anybody knows the solution it would help me loads. thanks
Your error is here:
swap :: String -> String -> [String] -> [String]
swap a b [] = []
swap a b (x:xs)
|x==a = [b] ++ xs -- <<< here
|x/=a = [x] ++ swap a b (xs)
When you find the word ayou are replacing it with b, but then you want to continue swapping on the remainder of the list.

How to use divide and conquer in parallel to calculate a/b as return for this list

implementing getReturnList and getReturnList2
getReturnList is for calculating return a/b in once
getReturnList2 is for advanced version using divide and conquer in parallel to increase
the speed to calculate return a/b that means it want to calculate in parallel in different
sublist of whole list
First error I do not understand that i pass x : [] to parameter [String]
compiler return this error
error for getReturnList
readcsv.hs:108:20:
Couldn't match type `Char' with `[Char]'
Expected type: [String]
Actual type: String
In the return type of a call of `getClose'
In the first argument of `(:)', namely `(getClose (x : []))'
In the expression:
(getClose (x : [])) : getReturnList (n - 1) total xs
readcsv.hs:108:30:
Couldn't match type `[Char]' with `Char'
Expected type: String
Actual type: [String]
In the first argument of `(:)', namely `x'
In the first argument of `getClose', namely `(x : [])'
In the first argument of `(:)', namely `(getClose (x : []))'
code:
import Control.Monad.Par
import Text.ParserCombinators.Parsec
import Data.Either.Unwrap
import System.IO
{- A CSV file contains 0 or more lines, each of which is terminated
by the end-of-line character (eol). -}
csvFile :: GenParser Char st [[String]]
csvFile =
do result <- many line
eof
return result
-- Each line contains 1 or more cells, separated by a comma
line :: GenParser Char st [String]
line =
do result <- cells
eol -- end of line
return result
-- Build up a list of cells. Try to parse the first cell, then figure out
-- what ends the cell.
cells :: GenParser Char st [String]
cells =
do first <- cellContent
next <- remainingCells
return (first : next)
-- The cell either ends with a comma, indicating that 1 or more cells follow,
-- or it doesn't, indicating that we're at the end of the cells for this line
remainingCells :: GenParser Char st [String]
remainingCells =
(char ',' >> cells) -- Found comma? More cells coming
<|> (return []) -- No comma? Return [], no more cells
-- Each cell contains 0 or more characters, which must not be a comma or
-- EOL
cellContent :: GenParser Char st String
cellContent =
many (noneOf ",\n")
-- The end of line character is \n
eol :: GenParser Char st Char
eol = char '\n'
parseCSV :: String -> Either ParseError [[String]]
--parseCSV :: String -> [[String]]
--parseCSV input = parse csvFile input
parseCSV input = parse csvFile "(unknown)" input
take3 :: Int ->[[String]] -> [String]
take3 0 _ = []
take3 _ [] = []
take3 n (x:xs)
| n == 1 = x
| n > 0 = take3 (n-1) xs
take3 _ _ = error "preludelist.take: negative argument"
returnlimiters = ['\n']
realtake2 :: Int -> [[String]] -> [String]
realtake2 x y = take3 x y
takeelem3 :: Int -> [String] -> String
takeelem3 0 _ = []
takeelem3 _ [] = []
takeelem3 n (x:xs)
| n == 1 = x
| n > 0 = takeelem3 (n-1) xs
takeelem3 _ _ = error "preludelist.take: negative argument"
realtakeelem2 :: Int -> [String] -> String
realtakeelem2 x y = takeelem3 x y
getOpen :: [String] -> String
getOpen x = realtakeelem2 2 x
getHigh :: [String] -> String
getHigh x = realtakeelem2 3 x
getLow :: [String] -> String
getLow x = realtakeelem2 4 x
getClose :: [String] -> String
getClose x = realtakeelem2 5 x
whitespace :: String
whitespace = ['\n','\t',' ']
forloop3 0 f = return()
forloop3 n f =
do
f n
forloop3 (n-1) f
getReturnList :: Int -> Int -> [[String]] -> [[String]]
getReturnList 0 _ _ = []
getReturnList _ _ [] = []
getReturnList n total (x:xs)
| n == total = getReturnList (n-1) total xs
| n > 0 = (getClose (x : [])) : getReturnList (n-1) total xs
getReturnList _ _ _ = error "preludelist.take: negative argument"
getReturnList2 :: Int -> Int -> [[String]] -> [[String]]
getReturnList2 0 _ _ = []
getReturnList2 _ _ [] = []
getReturnList2 n total (x:xs)
| n == total = getReturnList2 (n-1) total xs
| n > 0 =
do
p1 <- spawn (getReturnList2 n-1 total (filter (<x) xs))
p2 <- spawn (getReturnList2 n-1 total (filter (>=x) xs))
left <- get p1
right <- get p2
return $ left ++ (x:right)
getReturnList2 _ _ _ = error "preludelist.take: negative argument"
main = do
csvstring <- readFile "C:\\Users\\martin.lee\\Downloads\\0388.HK.csv"
let afterparse = parseCSV csvstring
let afterparse2 = fromRight afterparse
--putStrLn(show afterparse2)
let getline3 = realtake2 3 afterparse2
putStrLn(show getline3)
--putStrLn(getOpen getline3)
--putStrLn(getHigh getline3)
--putStrLn(getLow getline3)
putStrLn(getClose getline3)
--forloop3 5 (\c -> putStrLn(show (5-c)))
--putStrLn(show (take2b 3 2 3 afterparse2))
--let (as,bs) = splitAt (length grids `div` 2) afterparse2
let num = 5
putStrLn("begin getReturnList")
putStrLn(show ( "a" : []))
putStrLn(show (getReturnList 3 3 afterparse2))
putStrLn("end getReturnList")
--putStrLn(show (1 :: Float))
--putStrLn(show (getlines2 csvstring))
--putStrLn(show (take 1 (getlines2 csvstring)))
putStrLn("a")
update:
F# non-parallel version
let rec test2(xs : float list) =
if xs.Length > 3 then
let (list1, list2) = split1 (xs.Length/2) xs
let (list3, list4) = split1 (xs.Length/2-1) xs
let b1 = test2(list1) // would like to parallel these two function
let b2 = test2(list4) // would like to parallel these two function
b1 # b2
else
let b1 = xs |> Seq.windowed 2
|> PSeq.map (fun x -> x.[0]/x.[1])
|> PSeq.toList
b1

Resources