Why while loop is working randomly? - r

I am confused while my while loop is working randomly?
how.many<-function(fruit, number){
string<-paste("How many",fruit,"?",sep=" ")
fruit_number<-readline(string)
print("fruit number")
print(fruit_number)
print("number")
print(number)
while(fruit_number > number){
print("inside while")
print("fruit number")
print(fruit_number)
print("number")
print(number)
print("ERROR: too many for the budget")
string<-paste("How many",fruit,"?",sep=" ")
fruit_number<-readline(string)
}
return(as.numeric(fruit_number))
}
Here's when I call this function:
> source("fruit.R")
> how.many("apple",6)
How many apple ?3
[1] "fruit number"
[1] "3"
[1] "number"
[1] 6
[1] 3
> how.many("apple",10)
How many apple ?9
[1] "fruit number"
[1] "9"
[1] "number"
[1] 10
[1] "inside while"
[1] "fruit number"
[1] "9"
[1] "number"
[1] 10
[1] "ERROR: too many for the budget"
How many apple ?7
[1] "inside while"
[1] "fruit number"
[1] "7"
[1] "number"
[1] 10
[1] "ERROR: too many for the budget"
How many apple ?2
[1] "inside while"
[1] "fruit number"
[1] "2"
[1] "number"
[1] 10
[1] "ERROR: too many for the budget"
How many apple ?1
[1] 1
Any hint?

Convert fruit_number to a number, not a string.
e.g.
fruit_number <- as.numeric(readline(string))
or
fruit_number <- as.integer(readline(string))
Otherwise the numbers are compared as strings, and "9" is greater than "10" in the string sense.

Related

Function check for (length (list) != 0) always returns length = 0

I am using a UDF in an r-markdown script to plot data from stored lists. When I run my functions body, everything works out just fine, but when I try to execute the function with defined arguments, that I have verified to work in the body, all my logic that checks list length returns FALSE.
Here is an example data set I made:
library(dplyr)
library(plotly)
plotdataframe <- list()
dataframerows <- list()
AllExplVarCoeffs <- list()
AllExplVarNames <- list()
NrmPolcts <- list()
AllExplVarCoeff <- list()
AllExplVarName <- list()
NrmPolct <- list()
for (i in 1:10)
{
for (j in 1:8)
{
for(n in 1:16)
{
if (n == 3 || n == 8 || n == 4 && j == 5 || n == 9 && j == 5)
{
AllExplVarName <-NULL
AllExplVarCoeff <- NULL
NrmPolct <- NULL
}else
{
set.seed(10)
AllExplVarName <-c(1,2,3,4,5,6,7,8,9,10)
AllExplVarCoeff <- runif(10, min=-1, max=1)
NrmPolct <- c(.015,.005,.33,.32,.225,.025,.03,.05,0 ,0)
padvarcnt <-(length(AllExplVarCoeff)-length(NrmPolct))
for (l in seq_len(padvarcnt))
{
padval = l*0
NrmPolCt1 <- c(NrmPolCt,padval)
}
NrmPolct1 <- as.numeric(unlist(NrmPolct))
AllExplVarNames <- cbind(AllExplVarNames,AllExplVarName)
AllExplVarCoeffs <- cbind(AllExplVarCoeffs,AllExplVarCoeff)
NrmPolcts <- cbind(NrmPolcts,NrmPolct1)
dataframerows <- cbind(AllExplVarNames,AllExplVarCoeffs,NrmPolcts)
assign(paste("plotdataframe",i, j, n, sep="_"),cbind(plotdataframe,dataframerows))
plotdataframe <- list()
dataframerows <- list()
AllExplVarCoeffs <- list()
AllExplVarNames <- list()
NrmPolcts <- list()
assign(paste("AllExplVarNames",i, j, n, sep="_"),cbind(AllExplVarNames,AllExplVarName))
assign(paste("AllExplVarCoeffs",i ,j ,n, sep="_"),cbind(AllExplVarCoeffs,AllExplVarCoeff))
assign(paste("NrmPolcts",i, j, n, sep="_"),cbind(NrmPolcts,NrmPolct1))
AllExplVarCoeffs <- list()
AllExplVarNames <- list()
NrmPolcts <- list()
}
}
}
}
The NULL entries represent cases in my real data where the value for "n" would return an empty set.
My function is defined thus (please ignore the ugly plots, i'm pressed for time so I did not make this look nice):
DrawTestExVar <- function(x,j)
{
print(paste("x=",x))
print(paste("j=",j))
StCrPltData <- ls(pattern=paste0("plotdataframe_",x,"_",j))
SCPD <- mget(StCrPltData)
for(n in 1:16)
{ print(paste("n=",n))
print(paste0('plotdataframe_',x,'_',j,'_',n))
if (length(unlist((SCPD[c(paste0('plotdataframe_',x,'_',j,'_',n))]))) != 0)
{
n1=n
j1=j
print(n1)
plot1 <- plot_ly(as.data.frame(SCPD[c(paste0('plotdataframe_',x,'_',j,'_',n1))])) %>%
add_trace(x=~unlist(SCPD[c(paste0('plotdataframe_',x,'_',j,'_',n1))][[1]][,'AllExplVarName']), y=~unlist(SCPD[c(paste0('plotdataframe_',x,'_',j,'_',n1))][[1]][,'AllExplVarCoeff']), yaxis="y", type="scatter", mode="markers", name="Coef Values") %>%
add_bars(x=~unlist(SCPD[c(paste0('plotdataframe_',x,'_',j,'_',n1))][[1]][,'AllExplVarName']), y=~unlist(SCPD[c(paste0('plotdataframe_',x,'_',j,'_',n1))][[1]][,'NrmPolct1']), yaxis="y2", name="% Polcy Count")
print(plot1)
} else
{
print("Next")
}
}
}
but when I execute the function: DrawTestExVar(5,3) I get noting but the length = 0 response:
> DrawTestExVar(5,3)
[1] "x= 5"
[1] "j= 3"
[1] "n= 1"
[1] "plotdataframe_5_3_1"
[1] "Next"
[1] "n= 2"
[1] "plotdataframe_5_3_2"
[1] "Next"
[1] "n= 3"
[1] "plotdataframe_5_3_3"
[1] "Next"
[1] "n= 4"
[1] "plotdataframe_5_3_4"
[1] "Next"
[1] "n= 5"
[1] "plotdataframe_5_3_5"
[1] "Next"
[1] "n= 6"
[1] "plotdataframe_5_3_6"
[1] "Next"
[1] "n= 7"
[1] "plotdataframe_5_3_7"
[1] "Next"
[1] "n= 8"
[1] "plotdataframe_5_3_8"
[1] "Next"
[1] "n= 9"
[1] "plotdataframe_5_3_9"
[1] "Next"
[1] "n= 10"
[1] "plotdataframe_5_3_10"
[1] "Next"
[1] "n= 11"
[1] "plotdataframe_5_3_11"
[1] "Next"
[1] "n= 12"
[1] "plotdataframe_5_3_12"
[1] "Next"
[1] "n= 13"
[1] "plotdataframe_5_3_13"
[1] "Next"
[1] "n= 14"
[1] "plotdataframe_5_3_14"
[1] "Next"
[1] "n= 15"
[1] "plotdataframe_5_3_15"
[1] "Next"
[1] "n= 16"
[1] "plotdataframe_5_3_16"
[1] "Next"
I thought it was relatively straightforward; select the lists from the global environment with names that match the input pattern, then filter out the "n" values that return a length 0 list and plot the remainders in a loop. I have constructed two other functions to plot from stored data that work just fine, so I am confident the issue lies within the if else loop where the issue seems to be stemming from how I defined or am using my arguments. None of my digging into r function documentation has revealed what I am doing wrong though, and none of the attempts I have made to make the calls more explicit have worked.
Thoughts?
Update 1: After printing some troubleshooting statements, it is apparent that the error actually lies within the arguments being read or applied. When I print() the values for x and j when running the DrawTestExVar(5,3), x=5 and j=3, as needed. print()ing the value for n in the loop shows it incrementing appropriately and being applied to the paste commands correctly, but all the print(length(list)) return lengths of 0.
The answer lies within the way function is built and how it accesses data. The list references
StCrPltData <- ls(pattern=paste0("plotdataframe_",x,"_",j))
and
SCPD <- mget(StCrPltData)
need to occur outside of the function so it can actually access the dataframes. Furthermore, StCrPltData can be removed entirely by using its definition in the function call. The function arguments should look like
DrawTestExVar <- function(x,j,SCPD)
and to call the function
DrawTestExVar(5,3,mget(ls(pattern=paste0("plotdataframe_",5,"_",3))))
Running this gives the plots (which I will not show because they are very ugly), and the troubleshooting prints:
> DrawTestExVar(5,3,mget(ls(pattern=paste0("plotdataframe_",5,"_",3))))
[1] "x= 5"
[1] "j= 3"
[1] "n= 1"
[1] "plotdataframe_5_3_1"
[1] 1
[1] "n= 2"
[1] "plotdataframe_5_3_2"
[1] 2
[1] "n= 3"
[1] "plotdataframe_5_3_3"
[1] "Next"
[1] "n= 4"
[1] "plotdataframe_5_3_4"
[1] 4
[1] "n= 5"
[1] "plotdataframe_5_3_5"
[1] 5
[1] "n= 6"
[1] "plotdataframe_5_3_6"
[1] 6
[1] "n= 7"
[1] "plotdataframe_5_3_7"
[1] 7
[1] "n= 8"
[1] "plotdataframe_5_3_8"
[1] "Next"
[1] "n= 9"
[1] "plotdataframe_5_3_9"
[1] 9
[1] "n= 10"
[1] "plotdataframe_5_3_10"
[1] 10
[1] "n= 11"
[1] "plotdataframe_5_3_11"
[1] 11
[1] "n= 12"
[1] "plotdataframe_5_3_12"
[1] 12
[1] "n= 13"
[1] "plotdataframe_5_3_13"
[1] 13
[1] "n= 14"
[1] "plotdataframe_5_3_14"
[1] 14
[1] "n= 15"
[1] "plotdataframe_5_3_15"
[1] 15
[1] "n= 16"
[1] "plotdataframe_5_3_16"
[1] 16
which follow the expected output, showing the function to be working as desired.

How to flag missing left-hand collocates with NA

I want to compute collocates of the lemma GO, including all its forms such as go, goes, gone, etc.:
go <- c("go after it", "here we go", "he went bust", "go get it go", "i 'm gon na go", "she 's going berserk")
The lemma forms are stored in this vector:
lemma_GO <- c("go", "goes", "going", "gone", "went", "gon na")
and this vector turns them into an alternation pattern:
pattern_GO <- paste0("\\b(", paste0(lemma_GO, collapse = "|"), ")\\b")
However, when using the pattern with str_extract_all to extract the immediately left-hand collocate of GO, the extraction misses out on those strings where GO is the first word in the string and reoccurs later in the string:
library(stringr)
str_extract_all(go, paste0("'?\\b[a-z']+\\b(?=\\s?", pattern_GO, ")"))
[[1]]
character(0)
[[2]]
[1] "we"
[[3]]
[1] "he"
[[4]]
[1] "it"
[[5]]
[1] "'m" "na"
[[6]]
[1] "'s"
The expected result is this:
[[1]]
[1] NA
[[2]]
[1] "we"
[[3]]
[1] "he"
[[4]]
[1] NA "it"
[[5]]
[1] "'m" "na"
[[6]]
[1] "'s"
How can the extraction be mended to also return NA in the absence of a left-hand collocate?
You can add an alternative to match at the start of a string, or your consuming pattern:
str_extract_all(go, paste0("('?\\b[a-z']+\\b|^)(?=\\s?", pattern_GO, ")"))
See the regex demo.
See the R demo:
go <- c("go after it", "here we go", "he went bust", "go get it go", "i 'm gon na go", "she 's going berserk")
lemma_GO <- c("go", "goes", "going", "gone", "went", "gon na")
pattern_GO <- paste0("\\b(", paste0(lemma_GO, collapse = "|"), ")\\b")
library(stringr)
str_extract_all(go, paste0("('?\\b[a-z']+\\b|^)(?=\\s?", pattern_GO, ")"))
Output:
[[1]]
[1] ""
[[2]]
[1] "we"
[[3]]
[1] "he"
[[4]]
[1] "" "it"
[[5]]
[1] "'m" "na"
[[6]]
[1] "'s"
Sukces #stdin #stdout 0.26s 42528KB
[1] "\\b(go|goes|going|gone|went|gon na)\\b"
[[1]]
[1] ""
[[2]]
[1] "we"
[[3]]
[1] "he"
[[4]]
[1] "" "it"
[[5]]
[1] "'m" "na"
[[6]]
[1] "'s"
If you want, you can turn all empty items into NA using
res <- str_extract_all(go, paste0("('?\\b[a-z']+\\b|^)(?=\\s?", pattern_GO, ")"))
res <- lapply(res, function(x) ifelse(x=="", NA, x))

Filter list in R which has nchar > 1

I have a list of names
> x <- c("Test t", "Cuma Nama K", "O", "Test satu dua t")
> name <- strsplit(x, " ")
> name
[[1]]
[1] "Test" "t"
[[2]]
[1] "Cuma" "Nama" "K"
[[3]]
[1] "O"
[[4]]
[1] "Test" "satu" "dua" "t"
How can I filter a list so that it can become like this?
I am trying to find out how to filter the list which has nchar > 1
> name
[[1]]
[1] "Test"
[[2]]
[1] "Cuma" "Nama"
[[4]]
[1] "Test" "satu" "dua"
lapply(name, function(x) x[nchar(x)>1])
Results in:
[[1]]
[1] "Test"
[[2]]
[1] "Cuma" "Nama"
[[3]]
character(0)
[[4]]
[1] "Test" "satu" "dua"
We can loop over the list elements, subset the elements that have nchar greater than 1 and use Filter to remove the elements that 0 elements
Filter(length,lapply(name, function(x) x[nchar(x) >1 ]))
#[[1]]
#[1] "Test"
#[[2]]
#[1] "Cuma" "Nama"
#[[3]]
#[1] "Test" "satu" "dua"
If we want to remove the words with one character from the string, we can also do this without splitting
setdiff(gsub("(^| ).( |$)", "", x), "")
#[1] "Test" "Cuma Nama" "Test satu dua"

R: How to subset multiple elements from a list

> x
[[1]]
[1] "Bob" "John" "Tom"
[2] "Claire" "Betsy"
[[2]]
[1] "Strawberry" "Banana"
[2] "Kiwi"
[[3]]
[1] "Red"
[2] "Blue" "White"
Suppose I had a list x as shown above. I wish to subset the 2nd element of each entry in the list
x[[1]][2]
x[[2]][2]
x[[3]][2]
How can I do that in one command? I tried x[[1:3]][2] but I got an error.
Try
sapply(x2, `[`,2)
#[1] " from localhost (localhost [127.0.0.1])"
#[2] " from phobos [127.0.0.1]"
#[3] " from n20.grp.scd.yahoo.com (n20.grp.scd.yahoo.com"
#[4] " from [66.218.67.196] by n20.grp.scd.yahoo.com with NNFMP;"
data
x2 <- list(c("Received", " from localhost (localhost [127.0.0.1])"),
c("Received", " from phobos [127.0.0.1]"), c("Received",
" from n20.grp.scd.yahoo.com (n20.grp.scd.yahoo.com"),
c("Received", " from [66.218.67.196] by n20.grp.scd.yahoo.com with NNFMP;" ) )

Why cbind just shows the last row added to the data.frame in R?

I have written a function that takes the user budget and a grocery list and prompts user for the number of item she wants. This function has two problem currently. When I test it with 20 as budget I know I should be able to buy 10 spinach but it just allows me to buy 1 spinach. This is weird because I can buy the rest of items correctly. The second problem is that I want to show a data.frame of the purchased items by adding rows to it. However just the last purchased item is shown! Do you know how to fix these two problems?
how.many<-function(fruit, number){
string<-paste("How many",fruit,"?",sep=" ")
fruit.number<-readline(string)
print("fruit.number")
print(fruit.number)
print("number")
print(number)
while(fruit.number > number){
print("ERROR: too many for the budget")
string<-paste("How many",fruit,"?",sep=" ")
fruit.number<-readline(string)
}
return(as.numeric(fruit.number))
}
grocery.list <- function(file,budget) {
item.count<-0
updated.price=budget
#purchased.items <- data.frame(count= numeric(0), item= character(0), price = numeric(0),quantity=numeric(0))
purchased.items <- data.frame(count= numeric(0), item= character(0), price = numeric(0),quantity=numeric(0))
outf<-read.csv(file,header=FALSE)
colnames(outf)<-c("item","price")
mat = as.matrix(outf)
colnames(mat) <- NULL
for (i in 1:dim[1])
{
print(mat[i,2])
print(updated.price/as.numeric(mat[i,2]))
number=how.many(mat[i,1],updated.price/as.numeric(mat[i,2]))
print(number)
updated.price=updated.price- (number* (as.numeric(mat[i,2])) )
print(updated.price)
if (number>0){
item.count=item.count+1
purchased.items<-cbind(item.count,mat[i,1],as.numeric(mat[i,2]),number)
}
if (updated.price<=0){
break
}
}
colnames(purchased.items)=c(" ","item","price", "quantity" )
return(purchased.items )
}
n=grocery.list("groceries.csv",20)
print(n)
So the while loop in the how.many function doesn't work for the spinach here! I really don't get why because it works for the rest of the items.
Here's a sample for groceries.csv:
spinach,2.00
rice,3.00
toilet paper,4.00
bread,2.40
milk,3.10
apple,0.40
So here's a list of results I've got:
> source("grocery.R")
[1] "2.0"
[1] 10
How many spinach ?1
[1] "fruit.number"
[1] "1"
[1] "number"
[1] 10
[1] 1
[1] 18
[1] "3.0"
[1] 6
How many rice ?3
[1] "fruit.number"
[1] "3"
[1] "number"
[1] 6
[1] 3
[1] 9
[1] "4.0"
[1] 2.25
How many toilet paper ?4
[1] "fruit.number"
[1] "4"
[1] "number"
[1] 2.25
[1] "ERROR: too many for the budget"
How many toilet paper ?2
[1] 2
[1] 1
[1] "2.4"
[1] 0.4166667
How many bread ?5
[1] "fruit.number"
[1] "5"
[1] "number"
[1] 0.4166667
[1] "ERROR: too many for the budget"
How many bread ?1
[1] "ERROR: too many for the budget"
How many bread ?0
[1] 0
[1] 1
[1] "3.1"
[1] 0.3225806
How many milk ?2
[1] "fruit.number"
[1] "2"
[1] "number"
[1] 0.3225806
[1] "ERROR: too many for the budget"
How many milk ?1
[1] "ERROR: too many for the budget"
How many milk ?0
[1] 0
[1] 1
[1] "0.4"
[1] 2.5
How many apple ?0
[1] "fruit.number"
[1] "0"
[1] "number"
[1] 2.5
[1] 0
[1] 1
item price quantity
[1,] "3" "toilet paper" "4" "2"
how.many<-function(fruit, number){
string<-paste("How many",fruit,"?",sep=" ")
fruit.number<-as.numeric(readline(string))
while(fruit.number > number){
print("ERROR: too many for the budget")
string<-paste("How many",fruit,"?",sep=" ")
fruit.number<-as.numeric(readline(string))
}
return(as.numeric(fruit.number))
}
grocery.list <- function(file,budget) {
item.count<-0
updated.price=budget
final.price<-0
purchased.items <- data.frame(count= numeric(0), item= character(0), price = numeric(0),quantity=numeric(0))
outf<-read.csv(file,header=FALSE)
mat = as.matrix(outf)
colnames(mat) <- NULL
m.dim=dim(mat)
for (i in 1:m.dim[1])
{
if (updated.price-as.numeric(mat[i,2])>0)
{
number=how.many(mat[i,1],updated.price/as.numeric(mat[i,2]))
updated.price=updated.price- (number* (as.numeric(mat[i,2])) )
if (number>0){
item.count=item.count+1
new_row=data.frame(item=mat[i,1],price=as.numeric(mat[i,2]),quantity=number)
purchased.items<-rbind(purchased.items,new_row)
}
}
}
colnames(purchased.items)=c("item","price", "quantity" )
print(purchased.items)
print(purchased.items)
p.mat=as.matrix(purchased.items)
colnames(p.mat)<-NULL
rownames(p.mat)<-NULL
p.dim<-dim(p.mat)
for (i in 1:p.dim[1])
final.price<- final.price+ (as.numeric(p.mat[i,2]))*(as.numeric(p.mat[i,3]))
return(final.price)
}
gl=grocery.list("groceries.csv",10)
string<-paste("Your bill is $",gl,sep="")
print(string)

Resources