I wanted to write a function that splits a word into first, middle, and last characters and creating an individual list for each character. For example:
The word "codes" would be split into:
(list #\c "ode" #\s)
then
(list #\c \o "d" #\e #\s)
then
(list #\c \o #\d #\e #\s)
So basically it takes any word and then splits off the first and last character, then repeat the process until every character is converted. Could someone help me with this? Thanks
I'd love to help you with this. Here is my help:
You can differentiate between characters and strings using string? and char?
A string is a vector of characters. You can get the length with string-length and access individual characters with string-ref.
Strings and vectors are zero indexed like all good languages. Use + and - to calculate the needed index.
Use substring to create the new middle string.
You use car, cdr, and cons for the actual list parts.
Scheme only real looping construct is recursion. named let is often used in cases like this.
The logic should be to cons the first element nd recurse until you find a string. There you calculate the index of the last element. You then cons the first, cons the new middle, cons the new last letter, the rest of the list goes as the last cdr. You now have one round.
You need a outer loop if you want this to happen until the list no longer has a string it it. The inner loop needs to know what to do if you end up with the empty list.
Here is a procedure that iterates until it hits a string, then replaces it with another. Your inner loop would look much like it:
(define (replace-first-string lst replacement)
(let helper ((lst lst))
(cond ((null? lst) '())
((string? (car lst)) (cons replacement (cdr lst)))
(else (cons (car lst) (helper (cdr lst)))))))
(replace-first-string (list #\c "ode" #\s) "here")
; ==> (#\c "here" #\s)
This is not a very efficent procedure to make a list of characters. In Scheme we already have string->list which produces the same end result.
Related
I'm taking a course in functional programming and coming from OOP my brain hurts trying to solve something that I think is quite trivial but I'm just not understanding the concept here. This is an exercise I need to do for school
Given a phrase, in my case it is
"Pattern Matching with Elixir. Remember that equals sign is a match operator, not an assignment"
I need to check starting letters of every word for a matching pattern and apply specific modification depending on pattern.
Im not even entirely sure what my current code is producing, when I inspect x and y I sort of understand what the loops are doing, they have a list for every word of phrase and that inner list consists of checks against every single letter, nil if it doesnt start with that letter and modified word if it does.
OOP in me wants those loops not to return any "nil" and only return a single edited word in every iteration. In functional programming I cant break loops and force returns so I need to think about this in another way.
My question is how should I approach this problem from functional programming perspective?
In the beginning I get a list of words which form a phrase, then I wish to edit every word and in the end get a list again containing these edited words.
Maybe a pseudo-code-like structure on how to tackle this would help me understand underlying concepts.
Here is my current code:
#Task two
def taskTwo() do
IO.puts "Task Two"
IO.puts "Pattern Matching with Elixir. Remember that equals sign is a match operator, not an assignment"
IO.puts "Task Two\n...Editing Words ..."
phrase = String.downcase("Pattern Matching with Elixir. Remember that equals sign is a match operator, not an assignment") |> String.split()
x = for word <- phrase do
checkVowels(word)
end
y = for word <- phrase do
checkConsonants(word)
end
IO.inspect x
IO.inspect y
end
#check vowels
def checkVowels(word) do
vowels = ["a","e","i","o","u"]
for vowel <- vowels do
if String.starts_with?(word, vowel) do
word <> "ay "
end
end
end
#check consonants
def checkConsonants(word) do
consonants = ["b","c","d","f","g","h","j","k","l","m","n","p","q","r","s","t","v","w","x","z","y"]
for consonant <- consonants do
if String.starts_with?(word, consonant) do
edited = String.replace_prefix(word, consonant, "")
edited <> consonant <> "ay "
end
end
end
MOdifications I need to apply: First check for starting letter and apply modification, then check again an see if inside word there are any of the multiletter combinations
Words beginning with consonants should have the consonant moved to the end of the word, followed by "ay".
Words beginning with vowels (aeiou) should have "ay" added to the end of the word.
Some groups of letters are treated like consonants, including "ch", "qu", "squ", "th", "thr", and "sch".
Some groups are treated like vowels, including "yt" and "xr".
One possible way (maybe not the most efficient, but using some of the Elixir powers) is to use recursion and pattern matching.
So one possible way to solve the first part of your exercise.
defmodule Example do
#vowels ~w[a e i o u y]
#phrase "Pattern Matching with Elixir. Remember that equals sign is a match operator, not an assignment"
def task_two() do
phrase =
#phrase
|> String.downcase()
|> String.split()
|> Enum.reverse()
# splitting the first letter of each word
|> Enum.map(&String.split_at(&1, 1))
# pass the phrase and an accumulator as arguments
result = check_words(phrase, [])
IO.inspect(result)
end
# using recursion to traverse the list
# when the phrase have no more words, it will match the empty list
def check_words([], phrase) do
Enum.join(phrase, " ")
end
# pattern match on the first letter and using guards to decide if vowel
def check_words([{first_letter, rest_of_word} | rest_of_list], accumulator)
when first_letter in #vowels do
# call the function again, with the rest of the list
new_word = first_letter <> rest_of_word <> "ay"
check_words(rest_of_list, [new_word | accumulator])
end
# when the pattern does not match for vowels, it should be a consonant
def check_words([{first_letter, rest_of_word} | rest_of_list], accumulator) do
new_word = rest_of_word <> first_letter <> "ay"
check_words(rest_of_list, [new_word | accumulator])
end
end
You will need to skip/handle the commas and possible some more tweaks to be fully functional. But hope it helps as a general idea.
Notes:
write tests. They will really help you understand what the code is doing
Elixir is an amazing language. If you come from OOP may look strange in the beginning. This book: Programming Elixir is really good and will help you a lot if you want to progress quickly.
This question already has answers here:
Making a string concatenation operator in R
(5 answers)
Closed 2 years ago.
I'm a big fan of the + operator for string concatenation in Python. I would like to extend/customize the + operator to do the same thing in R.
Here's what I have so far:
`+` <- function(a, b){
if(is.numeric(a)){
sum(a, b)
}else{
paste0(a, b)
}
This works pretty well, but in some speed tests, performs poorly compared to the original/primitive +. So, how can I refer to the primitive + instead of sum() in the second line of the function? If I just use +, of course R gives me a node stack overflow from infinite recursion.
(The answer offered in the duplicate question is another alternative, cleaner perhaps in that it does not add another function.)
Save the primitive as another function. Here I'll use a "special" function %plus% (so that it can be inlined), but it could be simply plus if you'd prefer.
`%plus%` <- `+`
`+` <- function(e1, e2) if (is.numeric(e1)) `%plus%`(e1, e2) else paste0(e1, e2)
1+2
# [1] 3
'a'+'b'
# [1] "ab"
This question already has answers here:
The difference between bracket [ ] and double bracket [[ ]] for accessing the elements of a list or dataframe
(11 answers)
Closed 3 years ago.
In an R list, why does indexing with [n] instead of [[n]] not return the nth element as non-R-programmers would expect?
lfile <- list('fileA.xls', 'file2.xls', 'fileY.xls')
ll <- list(list(1,2), list(3), list(4,5,6), list(7,8))
lv <- list(c(1,2), c(3), c(4,5,6), c(7,8))
> lfile[2]
[[1]]
[1] "file2.xls" # returns SUBLIST, not n'th ELEMENT
> lfile[[2]]
[1] "file2.xls" # returns ELEMENT
Because in general l[n] returns a sublist (possibly of length one), whereas l[[n]] returns an element:
> lfile[2]
[[1]]
[1] "file2.xls" # returns SUBLIST of length one, not n'th ELEMENT
> lfile[[2]]
[1] "file2.xls" # returns ELEMENT
From R intro manual: 6.1 Lists:
It is very important to distinguish Lst[[1]] from Lst[1].
‘[[…]]’ is the operator used to select a single element,
whereas ‘[…]’ is a general subscripting operator.
Thus the former is the first object in the list Lst, and if it is a named list the name is not included. The latter is a sublist of the list Lst consisting of the first entry only. If it is a named list, the names are transferred to the sublist.
This is an R gotcha (R being different to other languages in a non-obvious and under-documented way), although as ever some R users will insist it's doing exactly what it says, (somewhere deep and unindexed) in the doc. However, the help-page for list only shows you how to create a list but does not show how to index into it(!) Only ?[ or ?Extract manpages actually tell you how to index into a list(!)
I have column values in my data frame like my_name_is_khan , hello|this|is|it and so on . How do I use str_extract to do this? When I use str_extract, this is what I get. When i do not exactly know the character length before the first special char (- or |), what do I do ?
str_extract("my-name-is-khan", pattern = "[a-z]{1,6}")
[1] "my"
I'm not sure that I understand the different outputs in these two scenarios:
(1)
pioneers <- c("GAUSS:1777", "BAYES:1702", "PASCAL:1623", "PEARSON:1857")
split <- strsplit(pioneers, split = ":")
split
(2)
pioneers <- c("GAUSS:1777", "BAYES:1702", "PASCAL:1623", "PEARSON:1857")
split <- lapply(pioneers, strsplit, split = ":")
split
In both cases, the output is a list but I'm not sure when I'd use the one notation (simply applying a function to a vector) or the other (using lapply to loop the function over the vector).
Thanks for the help.
Greg
To me it's to do with how the output is returned. [l]apply stands for list apply - i.e. the output is returned as a list. strsplit already returns a list as, if there were multiple :s in your pioneers vector, it's the only data structure that makes sense - i.e. a list element of each of the 4 elements of the vector and each list element contains a vector of the split string.
So using lapply(x, strsplit, ...) will always return a list inside a list, which you probably don't want in this case.
Using lapply is useful in cases where you expect the result of the function you're applying to be a vector of an undefined or variable length. As strsplit can see this coming already, the use of lapply is redundant, so you should probably know what form you expect/want your answer to be in, and use the appropriate functions to coerce the output in to the right data structure.
To make clear, the output of the examples you gave is not the same. One is a list, one is a list of lists. The identical result would be
lapply(pioneers, function(x, split) strsplit(x, split)[[1]], split = ":")
i.e. taking the first list element of the inner list (which is only 1 element anyway) in each case.