r function not return any result - r

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

Related

About missing value where TRUE/FALSE needed in R

I want to return the number of times in string vector v that the element at the next successive index has more characters than the current index.
Here's my code
BiggerPairs <- function (v) {
numberOfTimes <- 0
for (i in 1:length(v)) {
if((nchar(v[i+1])) > (nchar(v[i]))) {
numberOfTimes <- numberOfTimes + 1
}
}
return(numberOfTimes)
}
}
missing value where TRUE/FALSE needed.
I do not know why this happens.
The error you are getting is saying that your code is trying to evaluate a missing value (NA) where it expects a number. There are likely one of two reasons for this.
You have NA's in your vector v (I suspect this is not the actual issue)
The loop you wrote is from 1:length(v), however, on the last iteration, this will try the loop to try to compare v[n+1] > v[n]. There is no v[n+1], thus this is a missing value and you get an error.
To remove NAs, try the following code:
v <- na.omit(v)
To improve your loop, try the following code:
for(i in 1:(length(v) -1)) {
if(nchar(v[i + 1]) > nchar(v[i])) {
numberOfTimes <- numberOfTimes + 1
}
}
Here is some example dummy code.
# create random 15 numbers
set.seed(1)
v <- rnorm(15)
# accessing the 16th element produces an NA
v[16]
#[1] NA
# if we add an NA and try to do a comparison, we get an error
v[10] <- NA
v[10] > v[9]
#[1] NA
# if we remove NAs and limit our loop to N-1, we should get a fair comparison
v <- na.omit(v)
numberOfTimes <- 0
for(i in 1:(length(v) -1)) {
if(nchar(v[i + 1]) > nchar(v[i])) {
numberOfTimes <- numberOfTimes + 1
}
}
numberOfTimes
#[1] 5
Is this what you're after? I don't think there is any need for a for loop.
I'm generating some sample data, since you don't provide any.
# Generate some sample data
set.seed(2017);
v <- sapply(sample(30, 10), function(x)
paste(sample(letters, x, replace = T), collapse = ""))
v;
#[1] "raalmkksyvqjytfxqibgwaifxqdc" "enopfcznbrutnwjq"
#[3] "thfzoxgjptsmec" "qrzrdwzj"
#[5] "knkydwnxgfdejcwqnovdv" "fxexzbfpampbadbyeypk"
#[7] "c" "jiukokceniv"
#[9] "qpfifsftlflxwgfhfbzzszl" "foltth"
The following vector marks the positions with 1 in v where entries have more characters than the previous entry.
# The following vector has the same length as v and
# returns 1 at the index position i where
# nchar(v[i]) > nchar(v[i-1])
idx <- c(0, diff(nchar(v)) > 0);
idx;
# [1] 0 0 0 0 1 0 0 1 1 0
If you're just interested in whether there is any entry with more characters than the previous entry, you can do this:
# If you just want to test if there is any position where
# nchar(v[i+1]) > nchar(v[i]) you can do
any(idx == 1);
#[1] TRUE
Or count the number of occurrences:
sum(idx);
#[1] 3

If else loop error in R

I am trying to solve the question of compare triplets in R posted on hackerrank
Although I have outlined the entitre steps still its not giving correct result not in hackerrank and in RStudio also . can anyone tell me
A reproducible example
m = data.frame(ints = as.integer())
m <- structure(rbind(m,c(5,6,7)), .Names = names(m))
m <- structure(rbind(m,c(3,6,10)), .Names = names(m))
names(m) = c("no1","no2","no3")
enter## the output gives m as below
`no1 no2 no3
1 5 6 7
2 3 6 10
## I need to compare the corresponding values in both rows
#if m[1,1] != m[2,1] then I need to store 1 in a vector or dataframe
#if m[1,2] != m[2,2] then I need to store 1 in a vector or dataframe
#if m[1,3] != m[2,3] then I need to store 1 in a vector or dataframe
#so We will get output as [1,1]
## defining a vector to store output as below
g = c(0,0,0)
g = c(0,0,0)
> g
[1] 0 0 0
> g[1]
[1] 0
## so my answer is as below
if(m[1,1]== m[2,1]))
{
print("nothing")
}
else
{
(g[1] = 1)
}
if((m[1,2]==m[2,2]))
{
print("nothing")
}
else
{
(g[2] = 1)
}
if((m[1,3]==m[2,3]))
{
print("nothing")
}
else
{
(g[3] = 1)
}
g = data.frame()
g = c(0,0,0)
I get the following errors after every else
Error: unexpected 'else' in " else"
also g even takes value for middle value which it should never take
g
[1] 1 1 1
Can anyone explain what is going on why it is still placing 1 for middle value.
In R an end of line marks the end of an instruction unless there are open parenthesis, open braces or an unfinished instruction, such as else to signify otherwise.
Try
if(m[1,1]== m[2,1]) {
print("nothing")
} else
{
(g[1] = 1)
}
Or shorter
if(m[1,1]== m[2,1])
print("nothing") else
g[1] = 1
Your problem in any case is better solved by:
g <- as.numeric(m[1,] != m[2,])
# [1] 1 0 1

Gambling algorithm

I have a hard time figuring out how to write a program in R.
I am suppose to bet 1$ on red, if I win I get 1$ and bet again, if I lose I double my bet. The program supposed to run until I win 10$ or bet becomes greater than 100.
Here is my code:
W=0
B=1
for(i=sample(0:1,1)){
B<-1
W<-0
while(W<10 & B<=100){
if(i=1){
W<-W+B
B<-B
}else{
B<-2*B
}
print(B)
}
}
i determines if I lose or win. And I use print(B) to see the if program runs. At this point it doesn't, B just equals 1 no matter what.
To make the consequences of such gambling more obvious we can modify this program adding variables to store the total Win/Lose and the dynamics of this number.
W_dyn <- c() # will store cumulative Win/Lose dynamics
W. <- 0 # total sum of Win/Lose
step <- 0 # number of bet round - a cycle of bets till one of
# conditions to stop happen: W > 10 or B >= 100
while (abs(W.) < 1000)
{ B <- 1
while (W < 10 & B <= 100)
{ i <- sample(0:1, 1)
if (i == 1)
{ W <- W + B
B <- 1
} else
{ W <- W - B
B <- 2 * B
}
print(B)
}
W. <- W. + W
W <- 0
step <- step + 1
W_dyn[step] <- W.
cat("we have", W., "after", step, "bet rounds\n")
}
# then we can visualize our way to wealth or poverty
plot(W_dyn, type = "l")
BTW, with condition of maximum possible B < Inf such gambling is always a waste of money in long run.
Your for loop doesn't make sense in this context. You should take another sample each time in the while loop.
B = 1
W = 0
while(W<10 & B<=100){
i=sample(0:1,1)
if(i==1){
W<-W+B
B<-B
}else{
B<-2*B
}
print(B)
}
Also, in your original for loop you needed an extra right parentheses ) after the sample(0:1,1) before the loop started. Without it, the program doesn't run as expected.
Also, you should use == instead of = when describing logical equalities.

switch case: several equivalent cases expressions in r

In r-programming:
i want to use the same method to handle cases 1 and 10, ie, when the loop is in round 1 and then in 10 again. same for 2 and 11.
is there a way to have several case expressions being handled by the same method
for k == 1 and later also fo 10 it should use the first case and for k ==2 and later 11 it should use the second case. the above code doesn't work.
for(i in 1:x) {
switch(k,
"1", "10"= {
correct <- test[21,1]
current <- test[i-p,1]
if(all(correct == current)){
answers[i-p,k] <- c(1)
} else{
answers[i-p,k] <- c(0)
}
},
"2","11" ={
correct <- test[21,2]
current <- test[i,2]
if(all(correct == current)){
answers[i,k] <- c(1)
} else{
answers[i,k] <- c(0)
}
}
}
the same code for only one case expression works:
for(i in 1:x) {
switch(k,
"1" = {
correct <- test[21,1]
current <- test[i-p,1]
if(all(correct == current)){
answers[i-p,k] <- c(1)
} else{
answers[i-p,k] <- c(0)
}
},
"2" ={
correct <- test[21,2]
current <- test[i,2]
if(all(correct == current)){
answers[i,k] <- c(1)
} else{
answers[i,k] <- c(0)
}
}
}
in java we can use case 1 : case 2 to do that. how is it done in r?
i appreciate your help. alternatively i could also copy the code but don't want to if i can avoid it.
My personal choice would be to remap your k to the overlapping cases. Example:
k<-1:20
kmatch<-(k-1)%%9 +1
# [1] 1 2 3 4 5 6 7 8 9 1 2 3 4 5 6 7 8 9 1 2
Then feed kmatch to your case expression
The syntax is along the lines of
f = function(x)
switch(x, "1"=, "10"="first", "11"="eleventh", "none")
Note the equal sign after each named expression, other than the default value.
> f("1")
[1] "first"
> f("10")
[1] "first"
> f("11")
[1] "eleventh"
> f("12")
[1] "none"
This is documented in the third paragraph of the 'Details' section of ?switch.

argument of length 0 in for loop R

I have 2 vectors of numbers. The vector "v" shows when a process starts in seconds. Vector u shows how much time does the proces in the vector u works.
I want to creeate a vector saying how many process are working at each second.
so this toy example: I create a vector "total" thats starts in second 0 (nevermind the end of the vector) and I will save in each position how many processes work in that second. So for example, in the first position of the vector(time 0) my code says I will have 1 process.
v <- c(0,1,2,3,4,5)
u <- c(1.2, 0.1, 1.2, 1, 0.5, 0)
j = 1
total <- rep(0, times = 10)
begin <- integer()
end <- integer()
repeat{
begin<- v[j] +1
end <- begin + u[j]%/%1
for(i in begin:end){
if(total[i] == 0){ total[i] <-1}
else total[i] = total[i] +1
}
if(j ==length(v)) break
j = j+1
}
total
[1] 1 2 1 2 2 1 0 0 0 0
I got this error(not here, in the real case):
Error in begin:end : argument of length 0
(I tried using an if in case begin = end) but "for" should work for only one position.
What can be happening??
You can use seq.int instead of : in this case. For example:
for (a in seq.int(from=3, to=3)) {
print(a)
}
[1] 3

Resources