Shift alphabetical characters in string - r

Let's say I have a string:
s <- 'hello world zzz'
I want to shift the alphabetical characters up by one.
So:
a becomes b
b becomes c
c becomes d
d becomes e
and so on...
w becomes x
x becomes y
y becomes z
And:
z becomes a
The other condition is that if there is character that isn't in the alphabet (in this case the space), keep the characters as it is, so the space remains as a space.
Would all this be possible?
My desired output here would be:
ifmmp xpsme aaa
I have tried:
new <- c()
for (i in s)
{
new <- c(new, 'abcdefghijklmnopqrstuvwxyz'[which('abcdefghijklmnopqrstuvwxyz' == i) + 1])
}
print(new)
But it doesn't work... It outputs nothing.
Any ways of doing this?

chartr("abcdefghijklmnopqrstuvwxyz", "bcdefghijklmnopqrstuvwxyza", 'hello world zzz')
# [1] "ifmmp xpsme aaa"
(A function I've never had cause to use ...)

Related

Can't figure out how to format a for loop with if statements

I am in an intro to R course and the professor has not been much help. One of the questions on the latest homework has me stumped. The question is below, along with my answers so far.
8. [15 points] Given the following code,
#
# x <- rnorm(10)
#
# Do the following.
#
# (1) create a count vector named "count" of four elements and set each to 0 using the rep function.
# (2) using a for loop to process each value in the vector x, count how many times each of the following values occur in the vector x using an if statement.
# a. "value is between -1 and 1 inclusive"
# b. "value is between -2 and 2 inclusive, but not between -1 and 1",
# c. "value is between -3 and 3 inclusive, but not between -2 and -2", or
# d. "value is greater than 3 or less than -3".
# (3) print each of the four counts in the count vector using a while loop.
#
# For example, if the vector x contains the following ten values,
#
# 1.1478911 1.6183994 -2.3790632 -0.2566993 0.8923735
# -0.7523441 -0.7559083 0.9836396 1.0994189 2.5519972
#
# Then, the output should be as below.
#
# count[1] is 5
# count[2] is 3
# count[3] is 2
# count[4] is 0
x <- rnorm(10)
My answers:
(1) count <- c(rep(0,4))
(2)
for (count in x) {
if (x > -1 & x < 1) {
print(count[1])
}
I know there is something wrong with my code for part one but we haven't gone over anything like this in class and I have struggled to find a video for something like this. Please point me in the right direction and let me know what mistakes I have made, thanks so much!
You part one is correct. Maybe you can remove the initial c() from it.
x <- rnorm(10)
#Part 1
count <- rep(0,4)
#Part 2
for(i in x) {
if(i >= -1 && i <= 1)
count[1] <- count[1] + 1
else if(i >= -2 && i <= 2)
count[2] <- count[2] + 1
else if(i >= -3 & i <= 3)
count[3] <- count[3] + 1
else count[4] <- count[4] + 1
}
#Part 3
i <- 0
while (i < length(count)) {
i <- i + 1
print(sprintf('count[%d] is: %d', i, count[i]))
}
Note that there are better/efficient ways to do this but I think for the purpose of this exercise this is what your professor wants.
Each of the 4 slots in count is supposed to keep track of whether a value in x satisfies one of the 4 conditions listed (a. through d.).
If we were to speak it out loud, it'd go something like:
Look at element 1 in x (you can do that with x[1]). It's 1.1478911. This satisfies condition b., so add a 1 to the "b. counter", which is the second slot in count, or count[2].
Now look at element 2 in x (that's x[2])...(and so on, up to the last element in x).
To solve this task, you could just write out 10 statements, looking at each of the 10 elements in x separately, and update count on a case-by-case basis, but that is long and is hard to modify.
A for-loop is kind of like making a template for the spoken-out-loud part above. So instead of saying, "Ok, now we're on Element 3, let's see what the deal is", you can instead say, "Ok, now we're on Element i...", where i is just a temporary variable, a placeholder that only exists for the life of the for-loop. The i placeholder automatically takes on the value of the element in the vector we're iterating over.
If it's for (i in 1:3) then i will be 1, then 2, then 3.
If it's for (letter in c("a", "b", "c")), then letter will be "a", then "b", then "c".
So you can see that when you write for (count in x), that doesn't follow the rules of the for-loop. It's true that we'll want to update count at some point in the loop, but you've got it in the spot where our temporary placeholder is supposed to go. You can call that placeholder whatever you want, but i is common when looping over numbers, by convention.
Here's an example: the following code will start i at 1, and repeat the code inside the loop statement with new integers, until i gets to 10:
for (i in 1:10) {
print(paste("i is", i, "and the i'th value of x is", x[i]))
}
That should be enough to get you over the part you're stuck on.
A couple of additional hints:
f you want to know how many things are in a vector, such as x, you can use length(x) (try it, you will see the output is 10). So instead of doing: for(i in 1:10), you can swap out 10 for length(x).
count[3] <- count[3] + 1 adds 1 to whatever the current total is in the third element of count.
Good luck! Someone may post the answer to the whole problem, but if you want to work through each piece, I hope this is a good jump start for you.

r function not return any result

I have created the following function. R should return 1 as a result but I doesn't give any result?
phrasedis <- function(string, phrase1, phrase2,n) {
char1 <- unlist(gregexpr(phrase1,string))
char2 <- unlist(gregexpr(phrase2,string))
for ( i in 1: 2) {
for (j in 1: 2) {
pos1[i] <- sapply(strsplit(substr(text, 0,char1[i]-1),"\\s"),length)+1
pos2[j] <- sapply(strsplit(substr(text, 0,char2[j]-1),"\\s"),length)+1
dist <- pos2[i] - pos1[j]
a <- ifelse(pos1[i]>0 & pos2[j]>0 & dist>0 & dist<=6,1,0)
if (a==1) break
return(a)
}
}
}
text <- "phone rang a b c d e f z y z phone rang but no answer"
b <- sapply(text, FUN=function(str) phrasedis(str,"phone rang" , "no answer",6))
What it should do is return 1 if the distance between phone rang and no answer is less than 6 words, otherwise return 0.
Thank you very much for your help.
The logic of your function is wrong.
First of all, you put the return() statement inside the loop, so the loop stops always in the first iteration due to that return() statement.
Then, you don't create the vectors pos1 and pos2, so your function can't even work. The only reason you don't complain about an error, is because you have a pos1 and pos2 in your global environment probably.
But even when placing the return statement where it's supposed to go (at the end!) and creating a pos1 and pos2 vector of length 2, your function can't work because your loop is wrong.
You loop over 1 and 2, which doesn't make sense at all unless you have exact 2 matches for both phrase1 and phrase2 in string. Due to that and the fact there is only 1 match for phrase2, when j==2 the outcome of the substr(text, 0, char2[j] -1) is NA, which has an exact length of 1 so pos2[j] becomes 2. Meanwhile pos1[i] is still 1, which fulfills your condition and hence 1 is returned.
This is how you could do it:
phrasedis <- function(string, phrase1, phrase2,n) {
char1 <- gregexpr(phrase1,string)[[1]]
char2 <- gregexpr(phrase2,string)[[1]]
# -1 is returned if no match was found for either phrase
if(any(c(char1,char2) == -1)){
return(0)
}
# Calculate the end positions of the words
end1 <- char1 + attr(char1, "match.length")
#set a to 0
a <- 0
# loop over all matches in char1
for(i in seq_along(char1)){
# Find the closest match for phrase 2
thepos <- which.min(abs(char2 - end1[i]))
# get all words in between.
# Don't forget to trim white spaces before and after
inbetween <- trimws(substring(string, end1[i], char2[thepos]-1))
inbetween <- strsplit(inbetween,"\\s")[[1]]
if(length(inbetween) <= n){
a <- 1
break
}
}
return(a)
}
This is how it works:
> text <- "phone rang a b cd phone rang d e f g h i no answer"
> phrasedis(text,"phone rang" , "no answer",6)
[1] 1
> text <- " There is nothing in this text"
> phrasedis(text,"phone rang" , "no answer",6)
[1] 0
> text <- "No answer but the phone rang"
> phrasedis(text,"phone rang" , "no answer",6)
[1] 0

Loop with alternating object value in R

I am trying to create a loop in R that allows me to change the value of an object within the loop.
Below is an easy example to point out what exactly I mean by this. Print(x) stands for a rather extensive bulk of code, in which the value of x is needed for certain computations. However, while solution #1 works on paper, it is not usable in this context (because of sub loops). Is there any way to design a loop in R that resembles solution #2? Thanks a lot in advance!
1> x <- 1
2> while (x == 1)
3> {
4> print(x)
5> x <- 2
6> print(x)
7> x <- 3
8> print(x)
9> x <- 4
10> print(x)
11> if (x == 4)
12> break
13> }
Output
1
2
3
4
1> x <- 1
2> while (x == 1 || x == 2 || x == 3 || x == 4)
3> {
4> print (x)
5> x <- 2
#jump to line 2, ignore line 5, proceed with line 6
6> x <- 3
#jump to line 2, ignore line 6, proceed with line 7
7> x <- 4
#jump to line 2, ignore line 7, proceed with line 8
8> if (x == 4)
9> break
10> }
Output
1
2
3
4
It is somewhat hard to tell what exactly you want to do, but I'll give a shot, too. So you first might want to write a function that takes the value of x and does computations depending on the value of x (as far as I got it from your example, the computations/loops are not the same for all x).
x <- 1:4
fct <- function(x) {
if (x==1){
y <- x^2
}
if (x==2) {
y <- x + 2
}
if (x>2 & x < 5) {
y <- x*3 + 4
}
return(y)
}
Now loop over x:
sapply(x, fct)
Is that what you want?
I'm not sure it's gonna work because it's not clear exactly what you want to do, but could you try to put in a vector all the values you want to run print on? Like this:
my_values <- c(1,2,3,4)
for(x in my_values) {
print(x)
}
EDIT:
What I am gonna may be totally useless, but are you getting your next key from RODBC as well? If that's the case, suppose that you can get your next key with a function get_next_key and your data with get_data. I also assume that get_next_key returns NA if there is no more key (i.e you had the last key before). Would that work:
x = 1
while(!is.na(get_next_key(x))) {
data = get_data(x)
print(data)
x = get_next_key(x)
}
This first obviously works only for integer increments of x:
x <- 1
while (x <= 4){
print(x)
x <- x+1
}
For arbitrary values of x:
x1 <- c(1, 2, 3, 4)
### index x1 and move along this;
### at each step assign the value to y1 then
### do something with (print) it
for (i in seq_along(x1)) print(y1 <- x1[i])
Nothing really wrong with a for loop here and sometimes easier to read than apply

How do I print values in a list that are greater than a certain number along with the row name in R?

I am painfully new to R. I have a list of data, and I wrote a loop to find which values are greater than a certain number:
for (i in listname){
if(i > x)
print(i)
}
I would like for the printed values to also include the row name... how would I go about doing that?
Thanks for your patience.
Strangely, when the item itself is the iterator, the name is lost. If you instead iterate over the number of the item, print works as expected:
for (i in 1:length(listname)){
if (listname[i] > x){
print(listname[i]) # value with name
}
}
Once you've learned more about R, you will probably want to do this in a "vectorized" way, instead of using a loop:
idx <- which(listname > x) # row numbers
listname[idx] # values with names
or with logical subsetting
gt_x<- listname > x # TRUE or FALSE
listname[gt_x] # values with names
Example: Try this with
listname <- 1:10
names(listname) <- letters[1:10]
x <- 4
idx <- which(listname > x) # row numbers
listname[idx] # values with names
# e f g h i j
# 5 6 7 8 9 10

R: creating a named vector from variables

Inside a function I define a bunch of scalar variables like this:
a <- 10
b <- a*100
c <- a + b
At the end of the function, I want to return a,b,c in a named vector, with the same names as the variables, with minimal coding, i.e. I do not want to do:
c( a = a, b = b, c = c )
Is there a language construct that does this? For example, if I simply do return(c(a,b,c)) it returns an unnamed vector, which is not what I want. I currently have a hacky way of doing this:
> cbind(a,b,c)[1,]
a b c
10 1000 1010
Is there perhaps a better, less hacky, way?
Here's a function to do that for you, which also allows you to optionally name some of the values. There's not much to it, except for the trick to get the unevaluated expression and deparse it into a single character vector.
c2 <- function(...) {
vals <- c(...)
if (is.null(names(vals))) {
missing_names <- rep(TRUE, length(vals))
} else {
missing_names <- names(vals) == ""
}
if (any(missing_names)) {
names <- vapply(substitute(list(...))[-1], deparse, character(1))
names(vals)[missing_names] <- names[missing_names]
}
vals
}
a <- 1
b <- 2
c <- 3
c2(a, b, d = c)
# a b d
# 1 2 3
Note that it's not guaranteed to produce syntactically valid names. If you want that, apply the make.names function to the names vector.
c2(mean(a,b,c))
# mean(a, b, c)
# 1
Also, as with any function that uses substitute, c2 is more suited for interactive use than to be used within another function.

Resources