sorry for unclarity
myfunction should return index of elements in vector satisfy condition
myfunction <- function(vector,condition)
{
seq_along(vector)[vector == condition]
}
myfunction(vector == condition)
Error: object 'conditions' not found
I'm not sure exactly what you want your function to perform. Does it need to show which elements in a vector satisfy a condition (which is what which(vector == 10) would do)? If that is your intent, can you just do something like:
myfunction <- function(vector, condition){
which(vector == condition)
}
In any case, as far as I'm aware, you can't put a test condition in the parameter definitions of your function.
Related
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")))
I am aiming to define a function that essentially copies a row based on the number of selectable values in another table. Each new row will contain combinations of unique selectable values. I ran the following code on one measure, but plan to use a loop for multiple measures after I can successfully define a function. However, the function does not run, but I can chunk the code and it works fine. Thanks in advance!
output_template_v2<-output_template_v1
measure <- "A"
col <- "1"
add_selOptions_to_output<-function(output_template_v2, measure, col, attributes){
if (tolower(str_sub(attributes$Attribute,-4, -1)) == "_sel"){
selOptions<-attributes[attributes$Measure.Name ==measure & attributes$Attribute == col & attributes$Program == "Blue",]
}
if (length(selOptions$Attribute > 0)){
subcopy<- output_template_v2[output_template_v2$Measure == measure,]
output_template_v2<-output_template_v2[output_template_v2$Measure != measure,]
subcopy<-subcopy[rep(1, length(selOptions$Attribute)),]
}
for (i in seq_along(selOptions)){
subcopy[,col][i]<-selOptions$Attribute[i]
}
output_template_v2 <-rbind(output_template_v2, subcopy)
}
The function works — but it does not modify its function arguments, because function arguments are copied into the function. Instead, the function returns the modified table. This already works, but the assignment in the last line of your function is redundant, so remove it:
add_selOptions_to_output <- function (output_template_v2, measure, col, attributes) {
if (tolower(str_sub(attributes$Product.Attribute, -4L, -1L)) == "_sel") {
selOptions <- attributes[
attributes$Catalog.Measure.Name == measure &
attributes$Product.Attribute == col &
attributes$Program == "Blue", ]
}
if (length(selOptions$Attribute.Values > 0)) {
subcopy <- output_template_v2[output_template_v2$`Measure #` == measure, ]
output_template_v2 <- output_template_v2[output_template_v2$`Measure #` != measure, ]
subcopy <- subcopy[rep(1L, length(selOptions$Attribute.Values)), ]
}
for (i in seq_along(selOptions)) {
subcopy[, col][i] <- selOptions$Attribute.Values[i]
}
rbind(output_template_v2, subcopy)
}
Either way, you’ll need to assign the return value of the function back to the argument with which you’re calling it, e.g.:
tmpl = add_selOptions_to_output(tmpl, measure, col, attributes)
I'd like to detect the first iteration in a loop within a function from inside the body of the loop (i.e., without using some counter variable defined outside the loop), and in the most flexible possible manner.
Here would be one basic solution, just to demonstrate the idea:
vect = c('x', 'y', 'z')
for (elem in vect) {
print(elem)
isfirst(elem, vect)
}
isfirst = function(ele, vec) {
if (ele == vec[1]) {
print('this is the first cycle!')
} else {
print('this is NOT the first cycle!')
}
}
The "problem" with this is that I want this function to be easily reusable in any loop: that means that it should not need loop-specific arguments such as elem and vect. That is: another loop might use e.g. for (my_item in my_list) etc., and so then the isfirst arguments would need to be modified correspondingly, e.g. isfirst(my_item, my_list). The ideal way would be to just have an isfirst() without any arguments needed.
I'm not sure whether this is even possible, but I welcome any ideas.
(About why I need this: I would simply want to provide users with a function that behaves differently based on whether or not the iteration is the first, and that they can flexibly use in any loop and don't need to make even this small adjustment of changing the arguments.)
Well, here is the closest I could get:
vect = c('x', 'y', 'z')
for (elem in enum(vect)) {
print(elem)
isfirst()
}
enum = function(vec) {
assign("first_iteration", TRUE, envir = .GlobalEnv)
vec = mapply(c, 1:length(vec), vec, SIMPLIFY = FALSE) # this is just a small extra, not related to the question
return(vec)
}
isfirst = function() {
if (first_iteration == TRUE) {
print('this is the first cycle!')
assign("first_iteration", FALSE, envir = .GlobalEnv)
} else {
print('this is NOT the first cycle!')
}
}
But I'm still hoping for a better solution.
Please, I am trying to print a message based on an entry of a user.
I am studying for a test and I want to create a function that If I type an specific article( variable character) It will check over a set of vectors and print a message.
ExpfromUS <- function(x){
x <- readline("Check if your articles could be import or export to US. Entry the type of article that you want to ship: ")
a <- c(x == CBOExUS)
b <- c(x == RQSVExUS)
e <- c(x == NATExUS)
for ( i in length(a == TRUE)){
if (a[i] == TRUE){
print("Ok, but just with Contractual basis only");
break; }
else{ for (i in length(b)){
if (b[i] == TRUE){
print("Ok, but with restrictions of quantity, size or value");
break;}
else{ for (i in length(c)){
if (e[i] == TRUE){
print("Sorry, but we are not able to ship your cargo at this moment");
break;}
else{ print("Please check your entry we could not find this article in our database")
}}
}
}
}
}
}
But always print the last message "Please check your entry we could not find this article in our database", what am I doing wrong? (Sorry this is a beginner level doubt).
Thanks for all who spend their time helping me.
Expanding my comment: I suspect that your indexing for all the for loops is (part) the problem. The current indexing is only going to cause one iteration since length(a == TRUE) will return a single integer. I suspect you wanted the numeric values where "a == TRUE" so you could output a message at that row. The which function returns numeric values corresponding to the index of "TRUE" values of a logical vector, so perhaps you wanted:
for ( i in which(a) ){
....}
else{ for (i in which(b)){
...}
else{ for (i in which(c)){
....}
Further note: When working with logical vectors it is rarely necessary to include == TRUE and is sometimes going to return unexpected results when the vector includes NA's, since NA is never == to anything.
Given what you have offered as values for those three vectors I now thin it should have been
{....
a <- x %in% CBOExUS # the c() not needed. This returns a logical vector
b <- x %in% RQSVExUS
e <- x %in% NATExUS
.....
THe %in% function allows you to test for multiple values. The == function is asking if there is complete equality, obviously unlikely. There still may these correction be other flaws, but we're still without a [MCVE] and so we still won't be able to offer tested coding.
In the function shown below, there is no return. However, after executing it, I can confirm that the value entered d normally.
There is no return. Any suggestions in this regard will be appreciated.
Code
#installed plotly, dplyr
accumulate_by <- function(dat, var) {
var <- lazyeval::f_eval(var, dat)
lvls <- plotly:::getLevels(var)
dats <- lapply(seq_along(lvls), function(x) {
cbind(dat[var %in% lvls[seq(1, x)], ], frame = lvls[[x]])
})
dplyr::bind_rows(dats)
}
d <- txhousing %>%
filter(year > 2005, city %in% c("Abilene", "Bay Area")) %>%
accumulate_by(~date)
In the function, the last assignment is creating 'dats' which is returned with bind_rows(dats) We don't need an explicit return statement. Suppose, if there are two objects to be returned, we can place it in a list
In some languages like python, for memory efficiency, generators are used which will yield instead of creating the whole output in memory i.e. Consider two functions in python
def get_square(n):
result = []
for x in range(n):
result.append(x**2)
return result
When we run it
get_square(4)
#[0, 1, 4, 9]
The same function can be written as a generator. Instead of returning anything,
def get_square(n):
for x in range(n):
yield(x**2)
Running the function
get_square(4)
#<generator object get_square at 0x0000015240C2F9E8>
By casting with list, we get the same output
list(get_square(4))
#[0, 1, 4, 9]
There is always a return :) You just don't have to be explicit about it.
All R expressions return something. Including control structures and user-defined functions. (Control-structures are just functions, by the way, so you can just remember that everything is a value or a function call, and everything evaluates to a value).
For functions, the return value is the last expression evaluated in the execution of the function. So, for
f <- function(x) 2 + x
when you call f(3) you will invoke the function + with two parameters, 2 and x. These evaluate to 2 and 3, respectively, so `+`(2, 3) evaluates to 5, and that is the result of f(3).
When you call the return function -- and remember, this is a function -- you just leave the control-flow of a function early. So,
f <- function(x) {
if (x < 0) return(0)
x + 2
}
works as follows: When you call f, it will call the if function to figure out what to do in the first statement. The if function will evaluate x < 0 (which means calling the function < with parameters x and 0). If x < 0 is true, if will evaluate return(0). If it is false, it will evaluate its else part (which, because if has a special syntax when it comes to functions, isn't shown, but is NULL). If x < 0 is not true, f will evaluate x + 2 and return that. If x < 0 is true, however, the if function will evaluate return(0). This is a call to the function return, with parameter 0, and that call will terminate the execution of f and make the result 0.
Be careful with return. It is a function so
f <- function(x) {
if (x < 0) return;
x + 2
}
is perfectly valid R code, but it will not return when x < 0. The if call will just evaluate to the function return but not call it.
The return function is also a little special in that it can return from the parent call of control structures. Strictly speaking, return isn't evaluated in the frame of f in the examples above, but from inside the if calls. It just handles this special so it can return from f.
With non-standard evaluation this isn't always the case.
With this function
f <- function(df) {
with(df, if (any(x < 0)) return("foo") else return("bar"))
"baz"
}
you might think that
f(data.frame(x = rnorm(10)))
should return either "foo" or "bar". After all, we return in either case in the if statement. However, the if statement is evaluated inside with and it doesn't work that way. The function will return baz.
For non-local returns like that, you need to use callCC, and then it gets more technical (as if this wasn't technical enough).
If you can, try to avoid return completely and rely on functions returning the last expression they evaluate.
Update
Just to follow up on the comment below about loops. When you call a loop, you will most likely call one of the built-in primitive functions. And, yes, they return NULL. But you can write your own, and they will follow the rule that they return the last expression they evaluate. You can, for example, implement for in terms of while like this:
`for` <- function(itr_var, seq, body) {
itr_var <- as.character(substitute(itr_var))
body <- substitute(body)
e <- parent.frame()
j <- 1
while (j < length(seq)) {
assign(x = itr_var, value = seq[[j]], envir = e)
eval(body, envir = e)
j <- j + 1
}
"foo"
}
This function, will definitely return "foo", so this
for(i in 1:5) { print(i) }
evalutes to "foo". If you want it to return NULL, you have to be explicit about it (or just let the return value be the result of the while loop -- if that is the primitive while it returns NULL).
The point I want to make is that functions return the last expression they evaluate has to do with how the functions are defined, not how you call them. The loops use non-standard evaluation, so the last expression in the loop body you provide them might be the last value they evaluate and might not. For the primitive loops, it is not.
Except for their special syntax, there is nothing magical about loops. They follow the rules all functions follow. With non-standard evaluation it can get a bit tricky to work out from a function call what the last expression they will evaluate might be, because the function body looks like it is what the function evaluates. It is, to a degree, if the function is sensible, but the loop body is not the function body. It is a parameter. If it wasn't for the special syntax, and you had to provide loop bodies as normal parameters, there might be less confusion.