I would like to ask how I can overwrite the variables v and ind in the following function:
repcomb <- function(v,n,ind)
{
k <- length(v)
if(ind == 0)
{
for (i in 1:k) v[i] <- 1
ind <- 1
return
}
for (i in k:1)
{
if(v[i] != n)
{
for (j in k:i) v[j] <- v[i] + 1
return
}
}
ind = 0
}
What is the easiest way for updating v and ind?
This is the easiest way:
repcomb <- function(v,n,ind)
{
k <- length(v)
if(ind == 0)
{
for (i in 1:k) v[i] <- 1
ind <- 1
return(list(v=v, ind=ind))
}
for (i in k:1)
{
if(v[i] != n)
{
for (j in i+1:k) v[j] <- v[i] + 1
v[i] <- v[i] + 1
return(list(v=v, ind=ind))
}
}
ind = 0
return(list(v=v, ind=ind))
}
res <- repcomb(1:5, 4, 2)
v <- res$v
ind <- res$ind
If you want to get back the value of a parameter set inside a function, you can use eval.parent(substitute(val<-new_val)), for example:
f_sqr <- function(val){
new_val <- val^2
eval.parent(substitute(val<-new_val))
}
If you call it:
val <- 5
f_sqr(val)
val
#[1] 25
Please bear in mind that you should not change the value of the parameter inside the function, instead, you copy it to a new variable, do what you want to do in your code and finally set the value of new variable into your parameter variable as it is the case inside the function.
For your own function, this is what you have to do for your first if:
repcomb <- function(v, n, ind)
{
k <- length(v)
if (ind == 0)
{
new_v <- v
for (i in 1:k) new_v[i] <- 1
# ind <- 1
new_ind <- 1
eval.parent(substitute(ind<-new_ind))
eval.parent(substitute(v<-new_v))
}
}
Then if you call it, you will get the changes back:
v <- 1:5
n <- 3
ind <- 0
repcomb(v, n, ind)
v
#[1] 1 1 1 1 1
ind
#[1] 1
Correspondingly, the other part can be changed to meet what you want.
Related
I have written a code to find a positive integer that has more divisors than any smaller positive integer has. My code is right but I noticed that I wrote a step only because I had solved other questions similarly but I don't really understand the intuition of why we write this particular line:
b <- c()
Also, why is there a "b" in c(b, sum..) as in the below line:
b <- c(b, sum(p %% c(1:p) == 0))
Here is the full code:
code <- function(n) {
if (n < 1 | n %% 1 != 0)
print("Only positive integers allowed")
else if (n <= 2)
return(TRUE)
else {
a <- sum(n %% c(1:n) == 0)
b <- c()
for (p in 1:(n-1)) {
b <- c(b, sum(p %% c(1:p) == 0))
}
return(max(b) < a)
}
}
code(8)
code(6)
code(-7)
As already explained in comments the purpose of b<-c() is to initialise an empty vector and fill it in the loop. Also the reason why you are using b <- c(b,sum(p%%c(1:p)== 0)) is to append new values to already existing values of b.
For example,
b <- c()
b
#NULL
b <- c(b, 1)
b
#[1] 1
b <- c(b, 2)
b
#[1] 1 2
Usually, it is not a good practice to grow an object in a loop, it is highly inefficient to do that. If the size of output is fixed you can initialise a vector with fixed size and then fill it in the loop.
code <- function(n){
if (n<1 | n%%1!=0)
print("Only positive integers allowed")
else if (n <= 2)
return(TRUE)
else{
a <- sum(n%%c(1:n) == 0)
b <- integer(n-1) #Creates a vector with 0's of length n-1
for (p in 1:(n-1)) {
b[p] <- sum(p%%c(1:p)== 0)
}
return(max(b) < a)
}
}
Or in this case you can save only the max value of b since all other values are not important.
code <- function(n){
if (n<1 | n%%1!=0)
print("Only positive integers allowed")
else if (n <= 2)
return(TRUE)
else{
a <- sum(n%%c(1:n) == 0)
max_b <- 0
for (p in 1:(n-1)) {
val <- sum(p%%c(1:p)== 0)
if(val > max_b) max_b <- val
}
return(max_b < a)
}
}
It seems that I have a variable assignment problem when using the following code in a user-defined function.
The code below works fine and produces the right output when used directly in the R session:
# Code 1
n <- 1
n_final <- n
while(n < 3){
n_new <- n + 1
n_final <<- c(n_final, n_new); n <- n_new
}
n_final
[1] 1 2 3
However, when trying to wrap the code in a function, I obtain a wrong output:
# Code 2
fn <- function(){
n <- 1
n_final <- n
while(n < 3){
n_new <- n + 1
n_final <<- c(n_final, n_new)
n <- n_new
}
return(n_final)
}
fn()
# 1
I still obtain the wrong output when using the assign function:
# Code 3
fn <- function(){
n <- 1
n_final <- n
while(n < 3){
n_new <- n + 1
assign("n_final", c(n_final, n_new), envir = .GlobalEnv)
n <- n_new
}
return(n_final)
}
How could I insert the first code mentioned above in a function and get the same output?
<<- assigns to the global environment. When you call n_final inside the fn(), R first searches the function environment for a variable named n_final, and voila it finds:
n <- 1
n_final <- n
# ie. n_final is always 1 in the fn() environment
A solution to your error would be to use <- instead:
fn <- function(){
n <- 1
n_final <- n
while(n < 3){
n_new <- n + 1
n_final <- c(n_final, n_new)
n <- n_new
}
return(n_final)
}
fn()
Results in your expected output:
#> 1 2 3
Just remove the global assignment operator <<- and replace it with local <-
fn <- function(){
n <- 1
n_final <- n
while(n < 3){
n_new <- n + 1
n_final <- c(n_final, n_new)
n <- n_new
}
return(n_final)
}
fn()
[1] 1 2 3
*> csort <- function(c){
i<-1
for (i in 1:length(c)-1) {
j <- i+1
for (j in 2:length(c)) {
if(c[i] >= c[j])c[c(i,j)] <- c[c(j,i)]
j = j + 1
}
i = i + 1
}
}
> csort(a)
Error in if (c[i] >= c[j]) c[c(i, j)] <- c[c(j, i)] :
argument is of length zero*
This is what RStudio do when I run it. I do not know what cause the zero here.
csort <- function(c){
p <- 1
povit <- c[1]
c <- c[-1]
left <- c()
right <- c()
left <- c[which(c <= povit)]
right <- c[which(c > povit)]
if(length(left) > 1){
left <- csort(left)
}
if(length(right) > 1){
right <- csort(right)
}
return(c(left ,povit,right))
}
I viewed more about sorting online and this is a pivot sort way.
your mistake is in this line
for (i in 1:length(c)-1)
and should be
for (i in 1:(length(c)-1))
since $:$ operator precedes $-$.
an example is
1:(5-1)
#[1] 1 2 3 4
1:5-1
#[1] 0 1 2 3 4
so error happen in index with Zero value.
csort <- function(d){
for (i in 1:(length(d)-1)) {
for (j in (i+1):length(d)) {
if(d[i] >= d[j])d[c(i,j)] <- d[c(j,i)]
}
}
return(d)
}
d<-c(5:1,-1:3,-9,-3,10,9,-20,1,20,-6,5)
any((csort(d)==sort(d))==F)
#[1] FALSE
you can improve this function.
I have written a function to store the diagonal elements of a matrix into a vector. but the output is not as I expected. The code is:
diagonal <- function(x) {
for (i in nrow(x)) {
for (j in ncol(x)) {
if (i == j) {
a <- x[i, j]
}
}
}
print(a)
}
I am passing a matrix to the function.
What is wrong with the code?
We can use the diag function
diag(m1)
#[1] 1 5 9
Or
m1[col(m1)==row(m1)]
#[1] 1 5 9
If we are using the for loop, we are looping by the sequence of rows and columns i.e 1:nrow(x)/1:ncol(x) and not by nrow(x)/ncol(x).
diagonal <- function(x) {
a <- numeric(0)
for( i in 1:nrow(x)){
for(j in 1:ncol(x)){
if(i == j) {
a <- c(a, x[i,j])
}
}
}
a
}
diagonal(m1)
#[1] 1 5 9
data
m1 <- matrix(1:9, ncol=3)
x <- c(1,2,3,2,1)
table(x)
# x
# 1 2 3
# 2 2 1
Outputs how many times each element occur in the vector.
I am trying to imitate the above function using function()
Below is my code:
TotalTimes = function(x){
times = 0
y = unique(x)
for (i in 1:length(y)) {
for (i in 1:length(x)) {
if(y[i] == x[i])
times = times + 1
}
return(times)
}
}
What would be the right approach?
Here's a one-liner, using rle():
f <- function(x) {
with(rle(sort(x)), setNames(lengths, values))
}
f(c(1,2,3,2,1))
# 1 2 3
# 2 2 1
Alternatively, here's an option that's less "tricky", and is probably a better model for learning to code in an R-ish way:
f2 <- function(x) {
ss <- sort(x)
uu <- unique(ss)
names(uu) <- uu
sapply(uu, function(u) sum(ss == u))
}
f2(c(1,2,3,2,1))
# 1 2 3
# 2 2 1
function(x) {
q = sapply(unique(x), function(i) sum(x == i))
names(q) = unique(x)
return(q)
}
Here is one method using base R:
# data
x <- c(1,2,3,2,1)
# set up
y <- sort(unique(x))
counts <- rep_len(0, length.out=length(y))
names(counts) <- y
for(i in seq_along(x)) {
counts[x[i] == y] <- counts[x[i] == y] + 1
}
Wrapping it in a function:
table2 <- function(x) {
# transform x into character vector to reduce search cost in loop
x <- as.character(x)
y <- sort(unique(x))
counts <- rep_len(0, length.out=length(y))
names(counts) <- y
for(i in seq_along(x)) {
counts[x[i]] <- counts[x[i]] + 1L
}
return(counts)
}
This version only accepts a single vector, of course. At #Frank's suggestion, the function version is slightly different, and possibly faster, in that it transforms the input x into a character. The potential speed up is in the search in counts[x[i]] where the name in counts is referred to (as x[i]), rather than performing a search using "==."