Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 1 year ago.
Improve this question
My task is:
Implement the function puzz. It should simulate the game similar to 15 Puzzle. In our case, we have 25 squares, where 24 squares are occupied by tiles with big case letters from 'A' to 'X'. One tile is free and is denoted by ' '. In each move, you can move a tile (denoted by its letter) into the free space. The function gets the original configuration and a sequence of valid moves. It should output the resulting configuration.
I am new to Haskell, I can only do one first move.
Result after the last move must be ["ABCDE", "FGHIJ", "KLMNO", "PQRST ", "UVWX_"]. How to save the result of the first move and use it to do the second move, and the next, and then iterate some more?
s1 = ["AC DE",
"FBHIJ",
"KGLNO",
"PQMRS",
"UVWXT"]
p1 = "CBGLMRST"
puzz :: Result -> [Char] -> Result
puzz s1 p1 =
let i = 0
p = p1 !! i
change r = [ if c == ' ' then p else if c == p then ' ' else c | c <- r ]
out = [ change r | r <- s1 ]
in out
The s1 and the p1 in the puzz s1 p1 aren't your constants s1 and p1. They are only templates. For example puzz [" B"] "B" returns ["BB "] and p1 becomes [" B"] and s1 becomes "B" in that function call.
Don't try iterate (I removed part of code with the i). Use recursion. There are no variables in Haskell, only constants and input parameters. Input parameter (represented by the template) should be in each call different (closer to the end) because of referential integrity.
Don't forget to finish the algorithm.
(p:p1) - Template of input parameter which says that there is a nonempty list and the first character will be p and tail will be p1.
puzz s1 [] = s1 - When second parametr is empty list, then return first parameter (end).
puzz out p1 - Calling puzz for the changed s1 as out and p1 from (p:p1) (recursion).
s1 = ["AC DE","FBHIJ","KGLNO","PQMRS","UVWXT"]
p1 = "CBGLMRST"
puzz :: [String] -> [Char]-> [String]
puzz s1 (p:p1) = let
change r = [ if c == ' ' then p else if c == p then ' ' else c | c <- r ]
out = [ change r | r <- s1 ]
in puzz out p1
puzz s1 [] = s1
Output:
puzz s1 p1
=> ["ABCDE","FGHIJ","KLMNO","PQRST","UVWX "]
Related
Try to play with string and I have string like: "Hello.Word" or "stackOver.Flow"
and i what first char convert to lower case: "hello.word" and "stackOver.flow"
For snakeCase it easy we need only change UpperCase to lower and add '_'
but in camelCase (with firs char in lower case) i dont know how to do this
open System
let convertToSnakeCase (value:string) =
String [|
Char.ToLower value.[0]
for ch in value.[1..] do
if Char.IsUpper ch then '_'
Char.ToLower ch |]
Who can help?
module Identifier =
open System
let changeCase (str : string) =
if String.IsNullOrEmpty(str) then str
else
let isUpper = Char.IsUpper
let n = str.Length
let builder = new System.Text.StringBuilder()
let append (s:string) = builder.Append(s) |> ignore
let rec loop i j =
let k =
if i = n (isUpper str.[i] && (not (isUpper str.[i - 1])
((i + 1) <> n && not (isUpper str.[i + 1]))))
then
if j = 0 then
append (str.Substring(j, i - j).ToLower())
elif (i - j) > 2 then
append (str.Substring(j, 1))
append (str.Substring(j + 1, i - j - 1).ToLower())
else
append (str.Substring(j, i - j))
i
else
j
if i = n then builder.ToString()
else loop (i + 1) k
loop 1 0
type System.String with
member x.ToCamelCase() = changeCase x
printfn "%s" ("StackOver.Flow".ToCamelCase()) //stackOver.Flow
//need stackOver.flow
I suspect there are much more elegant and concise solutions, I sense you are learning functional programming, so I think its best to do stuff like this with recursive function rather than use some magic library function. I notice in your question you ARE using a recusive function, but also an index into an array, lists and recursive function work much more easily than arrays, so if you use recursion the solution is usually simpler if its a list.
I'd also avoid using a string builder, assuming you are learning fp, string builders are imperative, and whilst they obviously work, they wont help you get your head around using immutable data.
The key then is to use the pattern match to match the scenario that you want to use to trigger the upper/lower case logic, as it depends on 2 consecutive characters.
I THINK you want this to happen for the 1st char, and after a '.'?
(I've inserted a '.' as the 1st char to allow the recursive function to just process the '.' scenario, rather than making a special case).
let convertToCamelCase (value : string) =
let rec convertListToCamelCase (value : char list) =
match value with
| [] -> []
| '.' :: second :: rest ->
'.' :: convertListToCamelCase (Char.ToLower second :: rest)
| c :: rest ->
c :: convertListToCamelCase rest
// put a '.' on the front to simplify the logic (and take it off after)
let convertAsList = convertListToCamelCase ('.' :: (value.ToCharArray() |> Array.toList))
String ((convertAsList |> List.toArray).[1..])
The piece to worry about is the recusive piece, the rest of it is just flipping an array to a list and back again.
I have been trying to create a filter that checks if a phrase in a list of phrases exists in the text using recursive functions and match patterns, but somehow that does not seems to work... Maybe someone could give me hint why?
let rec matchTails (tail1 : string list) (tail2 : string list) =
match tail1, tail2 with
| h1::t1 , h2::t2 ->
if (h1=h2) then
matchTails t1 t2
else
false
| _, [] -> false
| [],_-> true
let rec check2 (textH: string) (textT: string list) (phrases: string list list) =
match phrases with
|[] -> ()
| h :: t ->
printfn "%s -- %s" (h.Head) (textH)
match h with
|x when x.Length = 1 && x.Head = textH ->
()
|x when x.Head = textH && (matchTails (textT) (x)) ->
printfn "%s" (x.Head)
| _ -> ()
check2 (textH) (textT) (t)
let rec check (phrases : string list list) (text:string list) =
match text with
| [] -> ()
| h :: t ->
check2 (h) (t) (phrases)
check phrases t
let p = [["rolex"]; ["free"; "spins"; "everyday"]; ["free"; "cash"]]
let t = ["hello";"and";"welcome";"to";"our";"annual";"free";"cash";"and";"rolex";"giveaway"]
Function call: check p t
I have edited my question with fixing few mistakes, but however, with these lists the program is giving unit() as an output...
There are some hints:
matchTails returns incorrect result for
matchTails [ "asdf1" ] [ "asdf" ] => true
matchTails [ "asdf" ] [ "asdf"; "asdf1" ] => true
matchTails [ ] [ "" ] => true
I suspect it should return false in all these cases. Probably the implementation you want is:
let rec matchTails (phrase : string list) (text : string list) =
match phrase, text with
| h1 :: t1, h2 :: t2 -> if h1 = h2 then matchTails t1 t2
else false
| [ ], _ -> true
| _ -> false
let matchTails_test () =
if not (matchTails [ "" ] [ "" ]) then raise Exception()
...
check2 is not called recursively so only the first phrase is checked
check is not called recursively, it calls check2 and returns
Generally, try to decompose problem into smaller functions and test each of them separately. You are moving in right direction, what is missing is clarity of what the each of the functions should do and test cases.
Update:
Note that check2 does not really return any value (it returns unit). Also it functionality overlaps with matchTails - it checks the head with the first word in the phrase, it is what matchTails does anyway.
check also returns unit, () means unit.
So let's rewrite check:
let rec check (phrases : string list list) (text : string list) =
if phrases |> List.exists (fun ph -> matchTails ph text) then
true
else
match text with
| [] -> false
| _ :: tail -> check phrases tail
While the question has now been basically answered, I would like to point out that its division into sub-problems is already very sufficient; shockingly lacking are the associated testing, and some descriptive naming of the individual functions tackling each sub-problem.
What about naming (and testing) matchTails, check2 and check exemplarily like this?
let ps = [["rolex"]; ["free"; "spins"; "everyday"]; ["free"; "cash"]]
let t = ["hello";"and";"welcome";"to";"our";"annual";"free";"cash";"and";"rolex";"giveaway"]
startsWithPhrase ["hello"; "and"] t
containsPhrase ["free"; "cash"] t
containsAnyPhrase ps t
Spoiler:
let rec startsWithPhrase phrase text =
match phrase, text with
| h1::t1, h2::t2 when h1 = h2 -> startsWithPhrase t1 t2
| [], _-> true
| _ -> false
let rec containsPhrase phrase text =
startsWithPhrase phrase text ||
match text with
| _::tl -> containsPhrase phrase tl
| [] -> false
let rec containsAnyPhrase phrases text =
match phrases with
| h::tl ->
containsPhrase h text ||
containsAnyPhrase tl text
| [] -> false
It may be much easier to stay completely with high-level functions, each in place of one recursive loop. Albeit here with a slighty different approach, dividing your haystack into needle-sized slices and comparing each of them with a given phrase.
let containsPhraseHL phrase text =
Seq.windowed (List.length phrase) text
|> Seq.exists (Seq.forall2 (=) phrase)
containsPhraseHL ["free"; "cash"] t
let containsAnyPhraseHL phrases text =
List.exists (fun phrase -> containsPhraseHL phrase text) phrases
containsAnyPhraseHL ps t
Basically, I have a loop that checks how many 'e' a user entered in one line. The thing is, I want it to show the total of e's entered total after every lines. Let's say he enters one line with 1 'e' in it the result will be 1, then after he enters the 2nd line that has 2 'e' in it, the total would be 3… and so on until the line is empty.
Here is my code so far. The problem with it: I don't know how to make a "total". I'm not sure if I'm clear... The current code will give the amount of 'e' found in each lines but not the total.
main = do
putStrLn "Enter your line"
line <- getLine
if line == ""
then return ()
else do
let v = nume line
main
print v
nume [] = 0
nume (x:xs)
|x == 'e' = 1 + nume xs
| otherwise = nume xs
Result:
Enter your line
there is 3 e
Enter your line
there are 4 e
Enter your line
only 1 e
Enter your line
1 <<-- Should be 8 (3+4+1)
4 <<-- Should be 7 (4+3)
3 <<-- ok
Somehow you need to add the accumulation. The simplest change would probably be to factor out the recursive action and parameterize over the total, which is initially 0. Something like this:
inner n = do
putStrLn "Enter your line"
line <- getLine
if line == ""
then return ()
else do
let v = n + nume line
inner v
print v
main = inner 0
nume [] = 0
nume (x:xs)
|x == 'e' = 1 + nume xs
| otherwise = nume xs
I am on the lookout for a gsub based function which would enable me to do combinatorial string replacement, so that if I would have an arbitrary number of string replacement rules
replrules=list("<x>"=c(3,5),"<ALK>"=c("hept","oct","non"),"<END>"=c("ane","ene"))
and a target string
string="<x>-methyl<ALK><END>"
it would give me a dataframe with the final string name and the substitutions that were made as in
name x ALK END
3-methylheptane 3 hept ane
5-methylheptane 5 hept ane
3-methyloctane 3 oct ane
5-methyloctane 5 ... ...
3-methylnonane 3
5-methylnonane 5
3-methylheptene 3
5-methylheptene 5
3-methyloctene 3
5-methyloctene 5
3-methylnonene 3
5-methylnonene 5
The target string would be of arbitrary structure, e.g. it could also be string="1-<ALK>anol" or each pattern could occur several times, as in string="<ALK>anedioic acid, di<ALK>yl ester"
What would be the most elegant way to do this kind of thing in R?
How about
d <- do.call(expand.grid, replrules)
d$name <- paste0(d$'<x>', "-", "methyl", d$'<ALK>', d$'<END>')
EDIT
This seems to work (substituting each of these into the strplit)
string = "<x>-methyl<ALK><END>"
string2 = "<x>-ethyl<ALK>acosane"
string3 = "1-<ALK>anol"
Using Richards regex
d <- do.call(expand.grid, list(replrules, stringsAsFactors=FALSE))
names(d) <- gsub("<|>","",names(d))
s <- strsplit(string3, "(<|>)", perl = TRUE)[[1]]
out <- list()
for(i in s) {
out[[i]] <- ifelse (i %in% names(d), d[i], i)
}
d$name <- do.call(paste0, unlist(out, recursive=F))
EDIT
This should work for repeat items
d <- do.call(expand.grid, list(replrules, stringsAsFactors=FALSE))
names(d) <- gsub("<|>","",names(d))
string4 = "<x>-methyl<ALK><END>oate<ALK>"
s <- strsplit(string4, "(<|>)", perl = TRUE)[[1]]
out <- list()
for(i in seq_along(s)) {
out[[i]] <- ifelse (s[i] %in% names(d), d[s[i]], s[i])
}
d$name <- do.call(paste0, unlist(out, recursive=F))
Well, I'm not exactly sure we can even produce a "correct" answer to your question, but hopefully this helps give you some ideas.
Okay, so in s, I just split the string where it might be of most importance. Then g gets the first value in each element of r. Then I constructed a data frame as an example. So then dat is a one row example of how it would look.
> (s <- strsplit(string, "(?<=l|\\>)", perl = TRUE)[[1]])
# [1] "<x>" "-methyl" "<ALK>" "<END>"
> g <- sapply(replrules, "[", 1)
> dat <- data.frame(name = paste(append(g, s[2], after = 1), collapse = ""))
> dat[2:4] <- g
> names(dat)[2:4] <- sapply(strsplit(names(g), "<|>"), "[", -1)
> dat
# name x ALK END
# 1 3-methylheptane 3 hept ane
I would like to paste two character strings together and pad at the end with another character to make the combination a certain length. I was wondering if there was an option to paste that one can pass or another trick that I am missing? I can do this in multiple lines by figuring out the length of each and then calling paste with rep(my_pad_character,N) but I would like to do this in one line.
Ex: pad together "hi", and "hello" and pad with an "a" to make the sequence length 10. the result would be "hihelloaaa"
Here is one option:
s1 <- "hi"
s2 <- "hello"
f <- function(x, y, pad = "a", length = 10) {
out <- paste0(x, y)
nc <- nchar(out)
paste0(out, paste(rep(pad, length - nc), collapse = ""))
}
> f(s1, s2)
[1] "hihelloaaa"
You can use the stringr function str_pad
library(stringr)
str_pad(paste0('hi','hello'), side = 'right', width = 10 , pad = 'a')