Search code examples
rfunctionassigncalling-convention

Calling an assigned variable created within a function in R, within the same function


I am writing a function to solve a Sudoku puzzle. Part of this function will be used to split the matrix into three 9x3 matrices. I shall then perform actions on each one prior to rejoining the matrices to one big matrix.

For this stage, I would like this part of my function to do three things:

  1. split the matrix into three matrices
  2. name each created matrix
  3. call the new matrices in the same function

However, I am struggling with step 3. I have written a function that will split the matrix into three, name each new matrix and if I put in the line envir = globalenv(), the function does return my matrix split into three, 9x3 matrices, each with its individual identifier name. Great!

However, what I would like to do in the next part of the function is to call the new matrices created by step 1 and 2 of the function. I will not know the name of the matrices prior to running the function as I'd like the code to be usable for many matrices no matter the size.

Is there a way of calling the objects created by the assign function, within the main function, when all I will know is that the objects' names will be "mat_n", with n being an integer.

For clarity, here is a simplified version of my code:

m <- matrix(sample(c(0:9), 81, replace = T), ncol = 9, nrow = 9)

matrix_split <- function(x){

  i <- 1:length(x[, 1])
  a <- 1:sum(i %% 3 == 0) # Will be used to name the temporary matrices
  b <- which(i %% 3 == 0) # Will be used to identify where to split main matrix


  for(n in a){  # This is to create a number of smaller matrices depending on the
                # number multiples of 3 that are present in the length of the object.

    nam <- paste("mat_", n, sep = "") # Each new matrix will be named and numbered
                                      # using the assign function below:

    assign(nam, x[, c((b[a[n]] - (sum(i %% 3 == 0) - 1)) : b[a[n]])])

    # Not a very elegant way of using the loop to split the matrix into blocks of
    # three. b[a[n]] returns either 3, 6 or 9, and (sum(i %% == 3) -1 ) = 2. So this
    # will return x[, c(1:3)], x[, c(4:6)] and x[, c(7:9)], when spliting the matrix
    # into three.

    }

}


matrix_split(m)

I am only asking for the specific solution to calling the objects created by the assign function, to be used within my main function after they have been created. This would be a useful skill and is a gap in my programming knowledge (which is not very extensive at all).

This may not be the best way of splitting a matrix either, and I know there are packages already created that will solve a Sudoku puzzle, but I'd like to write my own and there's no better way of learning than doing things badly at first and then improving on it.


Solution

  • How about using ls and parent.frame?

    mat_4 <- matrix(LETTERS[1:16],nrow=4)
    test <- function(){
    ls(parent.frame())[grep("mat_",ls(parent.frame()))]
    }
    test()
    # [1] "mat_4"
    get(test())
    #      [,1] [,2] [,3] [,4]
    # [1,] "A"  "E"  "I"  "M" 
    # [2,] "B"  "F"  "J"  "N" 
    # [3,] "C"  "G"  "K"  "O" 
    # [4,] "D"  "H"  "L"  "P" 
    

    Or if you want to include the current environment and every level higher, there is sys.frame().

    Edit

    To get around having to know the names of objects, maybe storing results in the elements of a list is a better plan.

    matrix_split <- function(x){
      i <- 1:length(x[, 1])
      a <- 1:sum(i %% 3 == 0) 
      b <- which(i %% 3 == 0)
      #initialize list
      result <- list()
      for(n in a){  
        # assign submatrix to element in the list
        result[[n]] <- x[, c((b[a[n]] - (sum(i %% 3 == 0) - 1)) : b[a[n]])]
        }
    do.call(cbind,result)
    }
    
    matrix_split(m)
          [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9]
     [1,]    6    4    2    9    1    2    8    0    4
     [2,]    8    5    5    8    6    1    3    7    8
     [3,]    4    7    1    8    3    6    6    0    6
     [4,]    3    0    5    0    6    3    2    3    9
     [5,]    0    9    7    7    0    1    5    3    2
     [6,]    0    8    8    9    9    8    4    9    8
     [7,]    6    0    2    9    9    2    4    8    9
     [8,]    6    9    6    4    8    1    2    1    1
     [9,]    8    4    6    8    5    0    9    5    9