I'm writing a code to solve a sudoku puzzle using a video found from YouTube that has coded the same algorithm through Python. This code requires three functions to
Find an empty square.
insert a number into the empty square.
Test whether this number is valid to solve the puzzle.
This is using a backtracking algorithm for the solver.
I am having an issue when calling the functions together where i get the error:
Error in free_squ(x) : argument "x" is missing, with no default
In addition: Warning message:
In if (empty_sq == FALSE) { :
the condition has length > 1 and only the first element will be used
Called from: free_squ(x)
This is confusing as I only get it when running thIS code. So I can write other functions to call the individual functions to analyse the argument inserted into the overlying function:
function1(argument){
function2(argument){
function3(argument){
***DO STUFF***}}}
Why for the following code does function within the main function not recognise the argument?
sudoku_solve <- function(x){
empty_sq <- free_squ(x) # Define a new object to give coordinates of empty square
if(empty_sq == FALSE){ # If no empty square can be found
return(x) # Return the matrix
} else{
empty_sq <- empty_sq # Pointless line kept for clarity
}
for(i in c(1:9)){ # Integers to insert into the found empty square
if(valid(x, i, empty_sq) == TRUE){ # can the intiger be placed in this square?
x[empty_sq[1], empty_sq[2]] = i # if i valid, insert into empty square
}
if(sudoku_solve()){ # are all i's valid?
return(TRUE) # All i's valid
} else{
x[empty_sq[1], empty_sq[2]] = 0 # reset the initial try and try again with another
}
}
return(FALSE)
}
I have named the sudoku puzzle 'puzzle', and call the function by the following:
sudoku_solve(puzzle)
I think in the following statement, you are not passing any value to the function and x does not have a default value either.
if(sudoku_solve()){ # are all i's valid?
return(TRUE) # All i's valid
}
Hence, although the argument is initially passed, when the function is called again after the loop, it is called without an argument. So you pass to free_sq(x) inside sudoku_solve(), and it gives an error.
empty_sq <- free_squ(x)
Make sure you are passing a value to sudoku_solve or else set the default value for x wither in sudoku_solve or in the free_squ class/function.
Related
I am creating a function in R for calculating compound interest using the equation - F=P\left(1+\frac{i}{100t}\right)^{ty}.
I need to create error messages if any of P, i, t, or y arguments are not numeric or negative, and an error if i is out of the range 0-100.
When I try to run the code i get the error message:
Error: unexpected ',' in:
" stop("Argument 'P','i','t' and 'y' must be numeric")
if(P,"
and am unsure how to fix it or what I have done wrong. The code so far is:
compound <- function(P,i,t=12,y,plotit=FALSE,...){
# 1. Check arguments and throw errors here using 'if' statements
if(!is.numeric(P,i,t,y)){
stop("Argument 'P','i','t' and 'y' must be numeric")
if(P,i,t,y<0){
stop("Argument 'P','i','t' and 'y' must be non-negative")
if(i<0||i>100){
stop("'i' must be within the range 0-100 percent")
}
}
}
if(plotit==TRUE){
# 2. Do plot if necessary here according to 'plotit' argument
y <- floor(y)
f <- P*((1+(i/100*t))^t*y)
for(i in length(y)){
plot(f, type = 's')
}
}
else {
final.result <- f
# Calculate final result here
return(final.result)
}
}
Any help on how to improve the code would be great!
The problem is that you are passing four arguments to is.numeric(P,i,t,y). It can take only one.
if(!all(sapply(list(P,i,t,y), is.numeric)))
That will check if all arguments are numeric.
A similar problem occurs with if(P,i,t,y<0), so use:
if(!all(sapply(list(P,i,t,y), function(x) x >= 0)))
Additionally, you have nested these if statements, which means the second and the third will not be evaluated. Move them out of your first if statement.
My dataset test[[1]] can be found here.
I'm defining a function and using it in a for loop in the following code. The function is supposed to concatenate strings such as (test[[1]], '$', names(test[[1]])[1])) before converting them into an R variable. So in this example, these strings go in and out comes test[[1]]$V1.
I then iterate the function over the variables in test[[1]].
Unfortunately, I keep getting this error: Error in stvar(test[[1]], j) <- NULL : could not find function "stvar<-".
stvar <- function(df,num) {
eval(parse(text=paste(deparse(substitute(df)),'$',names(df)[num],sep='')))
}
for (j in 1:length(names(test[[1]]))){
if (trimws(as.character(stvar(test[[1]],j)[1]))=="Div" &
grepl("^M",stvar(test[[1]],j)[3])==0) {
stvar(test[[1]],j) <- NULL
}
}
Also, not sure if this is important, but the for-loop finds columns containing certain characteristics (first observation == "Div", third observation doesn't start with 'M') and removes matching columns.
Is there a way I can make the loop recognize my function?
If my function has input (x,y,z) in R, I want to write a line of code which ensures data for x is of the right form.
i.e. x is just a real number rather than anything else such as a vector or a list. I assume the code would go something like
if ( ... ){stop("x must be a real number")}
I would like to know what goes inside of the bracket instead of ... ?
The reason is that if I write in a vector, the programme just take the first component of the vector as the input. R would give a warning about this, but I would like the programme to be stopped immediately.
If you want to "stop" if your argument is of length 1, and a real number
You could use stopifnot
foo <- function(x, y, z) {
stopifnot(length(x)==1L & is.numeric(x))
}
or perhaps
foo <- function(x, y, z){
if(!(length(x)==1L & is.numeric(x))) { stop("x must be a real number")}
}
stop allows you to specify the error message whereas stopifnot will return the condition that was tested. (Both have advantages)
The benefit of stopifnot is that it can tell you exactly which of multiple conditions failed.for example (noting that I am now feeding multiple expressions)
foo <- function(x, y, z) {
stopifnot(length(x)==1L , is.numeric(x))
}
foo('a')
# Error: is.numeric(x) is not TRUE
foo(c(1,2))
# Error: length(x) == 1L is not TRUE
I am trying to write a function which does different things, depending on the second argument. But I am getting an error all the time. Depending on the dimension of the matrix, the function should perform different tasks. Here is an example
x<-cbind(X1,X2,X3)
function<-function(x,hnrstr){
if (hnrstr<-1){
x<-data.frame(X1=x[1],X2=x[2],X3=x[3])
y<-x
y[ ,"X2","X3"]<- gsub(" {2, }"," ",y[ ,"X2","X3"])
}
if (hnrstr<-2){
x<-data.frame(X1=x[1],X2=x[2])
P<-x
}
if (hnrstr<-1){
x<-y
}
if (hnrstr<-2){
x<-P
}
return(x)
}
apply(x,c(3,3), function(x,1))
I am getting the error:
Error in drop && !has.j : invalid 'x' type in 'x && y'
hnrstr<-1 is assigning the value of 1 to hnrstr. You do not want this in an if statement. You either meant "test that hnrstr is less than minus one", in which case add some whitespace. hnrstr < -1, or you meant "test that hnrstr is equal to one", in which case use double equals, hnsstr == 1.
If X1, X2 and X3 are vectors, then x will be a matrix. That is, it has two dimensions. that means that later, after you've assigned y <- x (why do you need to do this?) y[ ,"X2","X3"]) doesn't make much sense because it implies that there are 3 dimensions, not two. This is what is causing the error. Did you mean y[, c("X2","X3")])?
gsub accepts a vector, so after you've changed the previous code, you also need to change the call to that function. Do you want to pass it the second column or the third column or both (one after the other)?
Those second if blocks look pointless. Have a think about how you can remove them.
if (hnrstr<-1){
x<-y
}
if (hnrstr<-2){
x<-P
}
You don't need a return statement at the end of the function. R automatically returns the last value that was calculated in the function.
As Colin said, don't try and call your function "function". That's just asking for trouble. Change the line
function <- function(x,hnrstr){
Can someone tell me what is wrong with this if-else loop in R? I frequently can't get if-else loops to work. I get an error:
if(match('SubjResponse',names(data))==NA) {
observed <- data$SubjResponse1
}
else {
observed <- data$SubjResponse
}
Note that data is a data frame.
The error is
Error in if (match("SubjResponse", names(data)) == NA) { :
missing value where TRUE/FALSE needed
This is not a full example as we do not have the data but I see these issues:
You cannot test for NA with ==, you need is.na()
Similarly, the output of match() and friends is usually tested for NULL or length()==0
I tend to write } else { on one line.
As #DirkEddelbuettel noted, you can't test NA that way. But you can make match not return NA:
By using nomatch=0 and reversing the if clause (since 0 is treated as FALSE), the code can be simplified. Furthermore, another useful coding idiom is to assign the result of the if clause, that way you won't mistype the variable name in one of the branches...
So I'd write it like this:
observed <- if(match('SubjResponse',names(data), nomatch=0)) {
data$SubjResponse # match found
} else {
data$SubjResponse1 # no match found
}
By the way if you "frequently" have problems with if-else, you should be aware of two things:
The object to test must not contain NA or NaN, or be a string (mode character) or some other type that can't be coerced into a logical value. Numeric is OK: 0 is FALSE anything else (but NA/NaN) is TRUE.
The length of the object should be exactly 1 (a scalar value). It can be longer, but then you get a warning. If it is shorter, you get an error.
Examples:
len3 <- 1:3
if(len3) 'foo' # WARNING: the condition has length > 1 and only the first element will be used
len0 <- numeric(0)
if(len0) 'foo' # ERROR: argument is of length zero
badVec1 <- NA
if(badVec1) 'foo' # ERROR: missing value where TRUE/FALSE needed
badVec2 <- 'Hello'
if(badVec2) 'foo' # ERROR: argument is not interpretable as logical