Sebastian Kranz
2010-Jul-25 13:04 UTC
[Rd] Redefine NROW and NCOL to be compatible with nrow and ncol for S3 classes with own dim function?
Dear R-developers, I am currently trying to develop a package with some customized container classes and found an issue with the functions NROW and NCOL. I guess that I can simply work around the problem by redefining these functions in my own package (Yet, I do not know whether that will work cleanly everywhere). Nevertheless, I thought that perhaps one might think about to redefine these functions in the base package. As example consider a class that shall behave like a matrix but will be copied by reference rather than by value (may be speed efficient, if a lot of functions manipulate the matrix). This can be done by wrapping the matrix in an environment and writing approbriate methods for dim, "[", etc. Here an example of some of its code # An example class that wraps a Matrix in an environment to allow pass by reference MatrixRef = function(mat) { m = new.env(parent=emptyenv()) assign("mat",mat,envir=m) class(m) = c("MatrixRef","environment") m } dim.MatrixRef = function(x) dim(get("mat",envir=x)) # ... define other functions like "[", "[<-", "length" etc. The functions nrow, ncol, NROW and NCOL are not (internally) generic, i.e. are difficult to overwrite. They rather make use of the generic functions dim (and length). However, nrow and NROW behave diferently: > #THE PROBLEM > #nrow works but NROW not > > m = MatrixRef(matrix(1:15,5,3)) > dim.MatrixRef(m) [1] 5 3 > nrow(m) # works [1] 5 > NROW(m) # Does not work [1] 1 I feel it is natural that NROW should behave like nrow and deliver dim(x)[1] if the object has a dim attribute. The reason for the problem is NROW treats special only matrix and data.frame but not every object that has a dim attribute. It is defined as follows in the base package: function (x) { if (is.array(x) || is.data.frame(x)) nrow(x) else length(x) } <environment: namespace:base> In my opinion, a good solution would be the following alternative specification: # Alternative definition of NROW ALTNROW = function(x) { d = dim(x) if (!is.null(d)) d[1] else length(x) } Here a check that it works for the Custom Class MatrixRef, as well as, a selection of alternative standard classes: > vec = runif(10) > mat = matrix(1:8,4,2) > df = data.frame(mat) > li = list("a","b") > > # Everything below works fine > ALTNROW(vec);ALTNROW(mat);ALTNROW(df);NROW(li) [1] 10 [1] 4 [1] 4 [1] 2 Indeed, it is seems to be even a bit faster than the current specification of NROW: > speed.NROW = function(R) { + for (i in 1:R) { + NROW(vec);NROW(mat);NROW(df);NROW(li) + } + } > speed.ALTNROW = function(R) { + for (i in 1:R) { + ALTNROW(vec);ALTNROW(mat);ALTNROW(df);NROW(li) + } + } > > system.time (speed.NROW(100000)) user system elapsed 5.13 0.00 5.26 > system.time (speed.ALTNROW(100000)) user system elapsed 3.84 0.00 3.85 For NCOL one could written a similar alternative specification. Best wishes, Sebastian --- Sebastian Kranz Department of Economics, University of Bonn http://www.wiwi.uni-bonn.de/kranz/ skranz@uni-bonn.de [[alternative HTML version deleted]]