why c() does not working in this recursive function in R? - r

enter image description here
I know there exists function 'unique' which works similar to what I want to make, but I want to make this function.
I want this function finally returns 'result' which contains unique elements of input vector.
But I don't know why this function's result is totally different from my expect.
Why c which is to combine before result and new unique element is not working.
Please tell me how to fix my code.
Thank you.

I think what you expect might be something like below, where result should be an argument of m_uni:
m_uni <- function(x,result = c()) {
if (class(x)=='numeric'| class(x)=='character') {
if (length(x) <= 1){
return(result)
} else {
if (x[length(x)] %in% result) {
x <- x[-length(x)]
m_uni(x,result)
} else {
result <- c(result,x[length(x)])
x <- x[-length(x)]
m_uni(x,result)
}
}
} else {
return('This function only gets numeric or character vector')
}
}
such that
> m_uni(x)
[1] 0 4 5 -2

Related

How do you generate the output of for loop and if statement into a list or vector?

I have tried the following but the output brings an argument stating,
Error in append("0") : argument "values" is miss
for (rowz in final_data$Ingridients) {
Cobalt_row<-lst()
if (sum(str_detect(rowz, 'Cobalt'))>0) {
Cobalt_row.append(1)
} else {
Cobalt_row<-append(0)
}
print(Cobalt_row)
}
I intended to loop through the list and generate a boolean of ones and twos depending on
whether or not I had the value.
Please help
Without the data, I can't test it, but this should work:
Cobalt_row<-lst()
k <- 1
for (rowz in final_data$Ingridients) {
Cobalt_row[[k]] <- ifelse(str_detect(rowz, 'Cobalt'), 1, 0)
k <- k+1
}
or even simpler if you need a list:
Cobalt_row <- as.list(as.numeric(str_detect(final_data$Ingredients, "Cobalt")))

Return() Not Working While Print() does after building a function in R

I'm working with panel data in R and am endeavoring to build a function that returns every user ID where PCA==1. I've largely gotten this to work, with one small problem: it only returns the values when I end the function with print() but does not do so when I end the function with return(). As I want the ids in a vector so I can later subset the data to only include those IDs, that's a problem. Code reflected below - can anyone advise on what I'm doing wrong?
The version that works (but doesn't do what I want):
retrievePCA<-function(data) {
for (i in 1:dim(data)[1]) {
if (data$PCA[i] == 1) {
id<-data$CPSIDP[i]
print(id)
}
}
}
retrievePCA(data)
The version that doesn't:
retrievePCA<-function(data) {
for (i in 1:dim(data)[1]) {
if (data$PCA[i] == 1) {
id<-data$CPSIDP[i]
return(id)
}
}
}
vector<-retrievePCA(data)
vector
Your problem is a simple misunderstanding of what a function and returning from a function does.
Take the small example below
f <- function(x){
x <- x * x
return x
x <- x * x
return x
}
f(2)
[1] 4
4 is returned, 8 is not. That is because return exits the function returning the specific value. So in your function the function hits the first instance where PCA[i] == 1 and then exits the function. Instead you should create a vector, list or another alternative and return this instead.
retrievePCA<-function(data) {
ids <- vector('list', nrow(data))
for (i in 1:nrow(data)) {
if (data$PCA[i] == 1) {
ids[[i]] <-data$CPSIDP[i]
}
}
return unlist(ids)
}
However you could just do this in one line
data$CPSIDP[data$PCA == 1]

In R, how to read multiple integers from user prompt?

I need to create a vector with multiple inputs (integers) from user.
The intent is to create a list and verify if it has a mode and where is its median.
I am using this code:
ReadVector <- function()
{
x <- 0
while(x<16) {
n <- readline(prompt="Input one integer: ")
return(as.integer(n))
VectorUser <- c(n)
x <- x+1
}
print(VectorUser)
}
ReadVector()
And I can only get one integer, I dont know if my mistake is in the while loop or(and) in the concatenate command after it. Can you help me?
Does this work for you?
ReadVector <- function()
{
x <- 0
myvector = vector()
while(x<16) {
n <- readline(prompt="Input one integer: ")
myvector = c(myvector,n)
x <- x+1
}
return (as.integer(myvector))
}
You need yo save your values in a vector, and keep it (without returning inside the loop), until you completed it.
Hope it helps
ff=function(){
d=c()
while (TRUE){
int = readline('ENTER to quit > ')
if(nchar(int)==0) {
if(length(d)>0)cat("The numbers you entered are:",d)
else(cat("You did not enter any number!!"));break}
else{
value=suppressWarnings(as.integer(int))
if(!is.na(value)){cat(value);d=c(d,value)} else cat(ran[sample(6,1)])
}}
ff()

What to set return value for function that normally returns matrix but could fail a conditional

I have a function that is supposed to return a matrix for further functions to use. I have it reading in a file and doing calculations, but I need the main function to skip to the next file if the current one does not meet the correct formatting. This is how basically how I have it now:
for (file in list.files(directory)) {
for (i in 1:length(var)) {
matrix <- foo('someFile.txt',var[i]) # returns matrix under normal conditions
if (typeof(matrix)) == "logical") { # check if foo returns FALSE
warning(paste0('File ',file, ' is not formatted correctly'))
break # skip to next file if so
}
...
}
}
foo <- function(input,seq)
data <- readLines(input)
if (!data[1] %in% c("first","line","values")) {
return(FALSE)
}
...
return(data)
}
But testing the class matrix returns seems clunky and poor technique. Sorry I don't know how to phrase the question better.

R -- screening Excel rows according to characteristics of multiple cells

I am trying to eliminate all rows in excel that have he following features:
First column is an integer
Second column begins with an integer
Third column is empty
The code I have written appears to run indefinitely. CAS.MULT is the name of my dataframe.
for (i in 1:nrow(CAS.MULT)) {
testInteger <- function(x) {
test <- all.equal(x, as.integer(x), check.attributes = FALSE)
if (test == TRUE) {
return (TRUE)
}
else {
return (FALSE)
}
}
if (testInteger(as.integer(CAS.MULT[i,1])) == TRUE) {
if (testInteger(as.integer(substring(CAS.MULT[i,2],1,1))) == TRUE) {
if (CAS.MULT[i,3] == '') {
CAS.MULT <- data.frame(CAS.MULT[-i,])
}
}
}
}
You should be very wary of deleting rows within a for loop, if often leads to undesired behavior. There are a number of ways you could handle this. For instance, you can flag the rows for deletion and then delete them after.
Another thing I noticed is that you are converting your columns to integers before passing them to your function to test if they are integers, so you will be incorrectly returning true for all values passed to the function.
Maybe something like this would work (without a reproducible example it's hard to say if it will work or not):
toDelete <- numeric(0)
for (i in 1:nrow(CAS.MULT)) {
testInteger <- function(x) {
test <- all.equal(x, as.integer(x), check.attributes = FALSE)
if (test == TRUE) {
return (TRUE)
}
else {
return (FALSE)
}
}
if (testInteger(CAS.MULT[i,1]) == TRUE) {
if (testInteger(substring(CAS.MULT[i,2],1,1)) == TRUE) {
if (CAS.MULT[i,3] == '') {
toDelete <- c(toDelete, i)
}
}
}
}
CAS.MULT <- CAS.MULT[-1*toDelete,]
Hard to be sure without testing my code on your data, but this might work. Instead of a loop, the code below uses logical indexing based on the conditions you specified in your question. This is vectorized (meaning it operates on the entire data frame at once, rather than by row) and is much faster than looping row by row:
CAS.MULT.screened = CAS.MULT[!(CAS.MULT[,1] %% 1 == 0 |
as.numeric(substring(CAS.MULT[,2],1,1)) %% 1 == 0 |
CAS.MULT[,3] == ""), ]
For more on checking whether a value is an integer, see this SO question.
One other thing: Just for future reference, for efficiency you should define your function outside the loop, rather than recreating the function every time through the loop.

Resources