Problem: how can I write a function that receives a and b as inputs and returns all integers inbetween them. So, assuming we have a function called integers_inbetween that behaves like this, we should expect the following examples:
# Returns an array of integers in between a and b
integers_inbetween(1, 4)
[1] 2 3
and
# Returns an array of integers in between a and b
integers_inbetween(4, 1)
[1] 2 3
And
# Returns NULL if there are no integers inbetween a and b
integers_inbetween(3.5, 4)
[1] NULL
How can one implement that logic in R?
This solution should work. I'm assuming the function should work if a > b and also if not. The way I wrote it, if after rounded a == b, the function returns NULL.
inbetween_integers <- function(a, b) {
a <- round(a)
b <- round(b)
if (abs(a - b) <= 1)
return(NULL)
if (b < a)
return(seq.int(from = b + 1, length.out = abs(a - b) - 1))
return(seq.int(from = a + 1, length.out = abs(a - b) - 1))
}
You can try the code below
inbetween_integers <- function(a, b) {
u <- sort(c(a, b))
res <- setdiff(ceiling(u[1]):floor(u[2]), c(a, b))
if (!length(res)) {
NULL
} else {
res
}
}
and you will see
> inbetween_integers(1, 4)
[1] 2 3
> inbetween_integers(4, 1)
[1] 2 3
> inbetween_integers(3.5, 4)
NULL
This works regardless of the order of arguments.
First this function sorts the arguments, then determines the minimum and maximum values in the sequence (exclusive of integer boundaries), then returns the sequence as requested.
integers_in_between<-function(x,y){
values<-sort(c(x,y))
minimum<-ifelse(ceiling(values[1])==values[1], ceiling(values[1])+1, ceiling(values[1]))
maximum<-ifelse(floor(values[2])==values[2], floor(values[2])-1, floor(values[2]))
if(maximum-minimum<0){
NULL
}else{
minimum:maximum
}
}
Related
I have a problem with a function of the following kind:
fun.name <- function(x,y) {
a<-x
b<-y
for (i in c(a, b)){
i<-i+1
print (i)
}
print(a)
print(b)
}
fun.name(1, 2)
The result is
[1] 2
[1] 3
[1] 1
[1] 2
The same result is obtained if I do not create any a and b and I simply keep x and y ( fun.name <- function(x,y) { for (i in c(a, b))...).
I cannot understand this behavior.
What I wanted was a function which adds one to every arguments and prints the results. Why does not the loop modify the variables a and b when it is defined within the function? I guess it is a problem of environments, and that I have not understood the nature of a function arguments.
Thank you for any suggestions.
I actually expect to see your current output. Here is your code, formatted, with explanations as comments:
fun.name <- function(x,y) {
a <- x
b <- y
for (i in c(a, b)) { # i in (1, 2)
# first iteration: i = 2, print 2
# second iteration: i = 3, print 3
i <- i+1
print(i)
}
print(a) # prints 1 (a was only assigned once)
print(b) # prints 2 (same reason as above)
}
fun.name(1, 2)
There are no changes to a and b after their initial assignments inside the function. But, even if there were changes, the variables a and b would not even be visible outside the scope of the function.
I'm trying to convert a while loop to a recursion.
I know the while loop is more efficient, but I'm trying to understand how to convert a for/while loop to recursion, and recursion to a for/while/if loop.
my function as I'm using a while loop:
harmon_sum <- function(x){
n <- 1
sum <- 0
while (sum < x)
{
sum <- sum + (1/n)
n <- (n +1)
}
return(n)
}
This function takes some numeric value, suppose x=2, and returns the number of objects for the harmonic sum that you need to sum up in order to create a greater number then x. (for x=2, you'd need to sum up the first 5 objects of the harmonic sum)
[![harmonic sum][1]][1]
**example**: `harmon_sum <- function(x){
n <- 1
sum <- 0
while (sum < x)
{
sum <- sum + (1/n)
print(sum)
n <- (n +1)
print(n)
}
return(n)
}
> harmon_sum(x =2)
[1] 1
[1] 2
[1] 1.5
[1] 3
[1] 1.833333
[1] 4
[1] 2.083333
[1] 5
[1] 5`
my version for the recursive function:
harmon_sum2 <- function(x, n =1){
if( x<= 0){
return(n-1)
}
else {
x <- (x- (1/(n)))
harmon_sum2(x, n+1)
}
}
which returns me the wrong answer.
I'd rather find a solution with just one variable (x), instead of using two variables (x, n), but I couldn't figure a way to do that.
It seems to me that if you change return(n-1) to return(n) you do get the right results.
harmon_sum2 <- function(x, n=1){
if( x <= 0){
return(n)
}
else {
x <- (x- (1/(n)))
harmon_sum2(x, n+1)
}
}
harmon_sum(2)
[1] 5
harmon_sum2(2)
[1] 5
harmon_sum(4)
[1] 32
harmon_sum2(4)
[1] 32
Your function needs to know n. If you don't want to pass it, you need to store it somewhere where all functions on the call stack can access it. For your specific case you can use sys.nframe instead:
harmon_sum2 <- function(x){
if( x<= 0){
return(sys.nframe())
}
else {
x <- (x- (1/(sys.nframe())))
harmon_sum2(x)
}
}
harmon_sum(8)
#[1] 1675
harmon_sum2(8)
#[1] 1675
However, this doesn't work if you call your function from within another function:
print(harmon_sum2(8))
#[1] 4551
Another alternative is the approach I demonstrate in this answer.
I have written a function in R like this:
foo <- function(a, b = 1) {
...
}
But now I want to change the default argument b, like:
foo(b = 2)
This is a function of a in principle. But R doesn't allow this, which throws me an error.
How can I fix it?
Your code in foo(b = 2) is function application: if everything works as expected, it will give you a value rather than a function.
You can modify the default values of arguments using formals:
foo <- function(a, b = 1) {
a + b
}
formals(foo)$b <- 2
foo
#function (a, b = 2)
# {
# a + b
# }
If you don't want to modify your foo directly, there are several options:
1) Copy first, change later
foa <- foo
formals(foa)$b <- 42
One might think of using "formals<-" as a shortcut but that can be complicated as you need to supply the full list of arguments (using alist rather than list because the former can take an empty argument):
"formals<-"(foo, , list(b=2)) # trying it with `list`
function (b = 2) # we lost one argument!
{
a + b
}
"formals<-"(foo, , alist(a=, b=42)) # this one is better!
function (a, b = 42)
{
a + b
}
2) Use purr::partial or function(a) foo(a,b=42) as recommended in the other answer.
3) And a third way ... one can actually write a very simple function (I'll call it p2) that changes some of the default arguments of a function and returns the changed function:
p2 <- function(f, l){
formals(f)[names(l)] <- l
f
}
p2(foo, list(b=42)) # changing a default: function (a, b = 42) a+b
p2(foo, alist(b=)) # removing a default: function (a, b) a+b
p2(foo, list(c="bingo") # adding an argument: function (a, b = 2, c = "bingo") a+b
A modified version:
p3 <- function(f, ...){
l <- as.list(sys.call())[-(1L:2L)] # code from `alist`
formals(f)[names(l)] <- l
f
}
Now the usage becomes shorter:
p3(foo, b=43) # function (a, b = 43) a+b
p3(foo, b=) # function(a,b) a+b
Note that p2 and p3 won't work properly with generic functions such as mean and min. This is probably the reason why the code in purrr:partial is so much more complicated.
You can call foo as so: foo(a, b = whatever)
If you need to change the default b to the same value really often, you could make a new foo-related function.
You could either define a new function:
# partially substitute in a `b` value
goo <- purrr::partial(foo, b = 2, .first = FALSE)
# or, a bit more explicitly,
hoo <- function(a) {foo(a, b = 2)}
or construct a function builder/factory, that allows you to build as many foo-related functions as you like
foo_builder <- function(b = 1) {
function(a) {
# your definition of foo goes here
blah <- blah_f(a, b)
}
}
Now you can pass in a b value to foo_builder and it will return the equivalent function to foo(a, b = whatever_you_passed_to_foo_builder)
goo <- foo_builder(2)
goo(a = ...)
For example,
foo_builder <- function(b = 1){
function(a){
message(b)
a + b
}
}
Now when the internal function is defined by foo_builder, it takes the value of b that is available to the foo_builder environment. This is 1 by default, but can be changed.
For example,
# default
foo_builder()(1)
1
[1] 2
# with b=2 in the closure returned by foo_builder
b <- 2
fb <- foo_builder(b)
fb(1)
2
[1] 3
A commenter suggested that you ought to force the evaluation of b when you make closures this way; because of the following:
b <- 2
fb <- foo_builder(b)
b <- 3
fb(1)
# 3
# [1] 4
So maybe rewrite the foo_builder:
foo_builder <- function(b = 1){
force(b)
function(a){
message(b)
a + b
}
}
I am having a problem implementing the ifelse command. I would like to return only positives (or 0) outputs. For example, in the following equation y=-50+(x^2), when y<=0, y should return 0. When y>0 it should return the proper output value. When I implement the following code:
test = function (x) 50+(x^2)
if(test <= 0) test <- 0 else y <-50+(x^2)
I always obtain 0.
A possible solution:
test <- function(x) (x ^ 2 > 50) * (x ^ 2 - 50)
test(5)
# [1] 0
test(10)
# [1] 50
Another approach:
test2 <- function(x) pmax(0, x ^ 2 - 50)
One solution
test = function(x) ifelse(0>(-50+x^2), 0, -50+x^2)
test(10)
[1] 50
test(100)
[1] 9950
Coming from various other languages, I find R powerful and intuitive, but I am not thrilled with its performance. So I decided to try to improve some snippet I wrote and learn how to code better in R.
Here's a function I wrote, trying to determine if a vector is binary-valued (two distinct values or just one value) or not:
isBinaryVector <- function(v) {
if (length(v) == 0) {
return (c(0, 1))
}
a <- v[1]
b <- a
lapply(v, function(x) { if (x != a && x != b) {if (a != b) { return (c()) } else { b = x }}})
if (a < b) {
return (c(a, b))
} else {
return (c(b, a))
}
}
EDIT: This function is expected to look through a vector then return c() if it is not binary-valued, and return c(a, b) if it is, a being the small value and b being the larger one (if a == b then just c(a, a). E.g., for
A B C
1 1 1 0
2 2 2 0
3 3 1 0
I will lapply this isBinaryVector and get:
$A
[1] 1 1
$B
[1] 1 1
$C
[1] 0 0
The time it took on a moderate sized dataset (about 1800 * 3500, 2/3 of them are binary-valued) is about 15 seconds. The set contains only floating-point numbers.
Is there anyway I could do this faster?
Thanks for any inputs!
You are essentially trying to write a function that returns TRUE if a vector has exactly two unique values, and FALSE otherwise.
Try this:
> dat <- data.frame(
+ A = 1:3,
+ B = c(1, 2, 1),
+ C = 0
+ )
>
> sapply(dat, function(x)length(unique(x))==2)
A B C
FALSE TRUE FALSE
Next, you want to get the min and max value. The function range does this. So:
> sapply(dat, range)
A B C
[1,] 1 1 0
[2,] 3 2 0
And there you have all the ingredients to make a small function that is easy to understand and should be extremely quick, even on large amounts of data:
isBinary <- function(x)length(unique(x))==2
binaryValues <- function(x){
if(isBinary(x)) range(x) else NA
}
sapply(dat, binaryValues)
$A
[1] NA
$B
[1] 1 2
$C
[1] NA
This function returns true or false for vectors (or columns of a data frame):
is.binary <- function(v) {
x <- unique(v)
length(x) - sum(is.na(x)) == 2L
}
Also take a look at this post
I'd use something like that to get column indicies:
bivalued <- apply(my.data.frame, 2, is.binary)
nominal <- my.data.frame[,!bivalued]
binary <- my.data.frame[,bivalued]
Sample data:
my.data.frame <- data.frame(c(0,1), rnorm(100), c(5, 19), letters[1:5], c('a', 'b'))
> apply(my.data.frame, 2, is.binary)
c.0..1. rnorm.100. c.5..19. letters.1.5. c..a....b..
TRUE FALSE TRUE FALSE TRUE