I am trying to create a program that takes in a list of strings. The strings contains of spacing and n chars
, either '*'
, '#'
, or '|'
, depending on the lists. So, given two lists, e.g..
[" # "," # # " ," # # # " ," # # # # " ," # # # # #" ]
[" | "," | "," | "," | ", " | "]
My switch
method would find the first string which contains '#'
in the first list, and put it in front of the other '#'
-containing strings in the other list. And if there were none, then we put the '#'
-containing string behind all the '|'
strings in the list.
In other words this models the Towers of Hanoi move from one pole to another where '|'
shows an empty pole and '#'
stands for a disk.
Thus the goal here is to move the top-most disk from the first pole onto the top-most disk on the other pole, if any; or otherwise put the moved disk on the bottom.
My code:
-- Switches elements from two lists, returns a list with the two new lists inside
switch :: [String] -> [String] -> [[String]]
switch [] [] = []
switch xs ys =
let
e1 = fromJust (findStr '#' xs) -- Find the first string in list that contains '#'
e2 = fromJust (findStr '|' $ reverse ys) -- Find the first string in the reversed list that contains '|'
newX = e2 : tail xs -- New list with its head replaced by e2
newY = tail ys : [[e1]] -- New list with its last string which contains '|' replaced by e1
in
newX : newY
--Finds and returns the string to be switched
findStr :: Char -> [String] -> Maybe String
findStr c xs = listToMaybe [s | s <- xs, c `elem` s]
When I run it, I get this actual output:
switch [" # " ," # # " ," # # # " ," # # # # " ," # # # # #"]
[" | "," | "," | "," | "," | "]
ghci> [[" | "," # # " ," # # # " ," # # # # " ," # # # # #"],
[" | "," | "," | "," | "],
[" # "]]
Desired output:
switch [" | "," # # " ," # # # " ," # # # # " ," # # # # #"]
[" | "," | "," | "," | "," # "]
ghci> [[" | "," | " ," # # # " ," # # # # " ," # # # # #"],
[" | "," | "," | "," # # "," # "]]
If I try to write it like this:
newY = tail ys : e1 -- New list with its last string which contains '|' replaced by e1
(Removed the brackets surrounding e1
)I get an error saying:
• Couldn't match type ‘Char’ with ‘[String]’
Expected: [[String]]
Actual: String
What am I doing wrong here? All help is appreciated!
CodePudding user response:
This code solves the issue I had:
-- Switches elements from two lists, returns a list with the two new lists inside
switch :: [String] -> [String] -> [[String]]
switch [] [] = []
switch xs ys =
let
rs = reverse ys
(e1, n1) = findStr '#' xs -- Find the first string in list that contains '#'
(e2, n2) = findStr '|' rs -- Find the first string in the reversed list that contains '|'
newX = e2 : (take (n1-1) xs drop n1 xs) -- New list with its head replaced by e2
newY = [reverse (take (n2-1) rs [e1] drop n2 rs)] -- New list with its last string which contains '|' replaced by e1
in
newX : newY
--Finds and returns the string to be switched
findStr :: Char -> [String] -> (String, Int)
findStr c xs = head [s | s <- zip xs [1..], c `elem` fst s]
CodePudding user response:
Regardless of your issues with the specific code you posted, a simple way to solve your problem is to use span
(or break
), then combine the two resulting tuples' components with
:
move :: [String] -> [String] -> Maybe ([String], [String])
move xs ys
| ( (a,h:b) , (c,d) ) <- (break (elem '#') xs,
break (elem '#') ys)
= Just (a b, c [h] d)
| otherwise
= Nothing
So that now we have,
> move [" # "," # # "," # # # "] [" | "," | "," | "]
Just ([" # # "," # # # "],[" | "," | "," | "," # "])
> move [" | "," # "," # # # "] [" | "," | "," | "," # # "]
Just ([" | "," # # # "],[" | "," | "," | "," # "," # # "])
> move [" | "," | "," | "] [" # "," # # "," # # # "]
Nothing
This code uses pattern guards.
I've also changed the output type.