[R] [newbie] stack operations, or functions with side effects (or both)
Martin Morgan
mtmorgan at fhcrc.org
Thu Jan 5 19:37:35 CET 2012
On 01/05/2012 09:18 AM, Tom Roche wrote:
>
> William Dunlap Wed, 4 Jan 2012 22:54:41 +0000
>> R functions [can] use their enclosing environments to save state.
>
> Aha!
>
>> makeStack<- function () {
>> stack<- list()
>> list(pop = function() {
>> if (length(stack) == 0) { # get from an enclosing env.
>> retval<- NULL
>> } else {
>> retval<- stack[[length(stack)]] # get from an enclosing env.
>> stack<<- stack[-length(stack)] # assign in an enclosing env.
>> }
>> retval
>> }, push = function(x) {
>> stack[[length(stack) + 1]]<<- x # assign in an enclosing env.
>> invisible(x)
>> })
>> }
>
> Thanks, that's quite clear.
One point is that subsetting with "[" or extending with
stack[[length(stack) + 1]] triggers a copy of stack. Better to pre-allocate
stack <- vector("list", 100)
curr <- 0L
and fill, e.g., push with
curr <<- curr + 1L
stack[[curr]] <<- x
plus bounds check and perhaps growth when necessary.
>
>> There are various encapsulations of this method in R. See, e.g.,
>> "reference classes" or the "proto" package.
>
> I can't see a reference-class implementation, but I did find
Probably Bill was pointing to ?ReferenceClasses. My attempt at
implementing a stack as a reference class led, ironically, to copying
issues anyway (below; maybe there's a different implementation?)
Efficient R programming usually involves operations on vectors, rather
than the iteration implied by a stack. This might change your conclusion
that a stack-based solution is appropriate.
Martin
Reference class implementation
.Stack <- setRefClass("Stack",
fields=list(stack="list", curr="integer"),
methods=list(
initialize=function(stackSize=100L, ...) {
callSuper(stack=vector("list", stackSize), curr=0L, ...)
},
push=function(val) {
curr <<- curr + 1L
if (curr > length(stack))
## double size; could be a bad choice
length(stack) <<- 2L * length(stack)
stack[[curr]] <<- val
invisible(val)
},
pop=function() {
if (curr == 0L)
NULL # sentinel: empty
else {
val <- stack[[curr]]
curr <<- curr - 1L
val
}
},
show=function() {
cat("Class:", class(.self), "\n")
cat("current size:", .self$curr, "\n")
cat("maximum size:", length(.self$stack), "\n")
if (.self$curr) {
cat("head:\n")
print(.self$stack[[1L]])
}
}))
and then
> stack <- .Stack$new()
> tracemem(stack$stack)
[1] "<0x1afc090>"
> stack$push(10)
tracemem[0x1afc090 -> 0x9283a0]: <Anonymous>
tracemem[0x9283a0 -> 0xb96450]: <Anonymous> <Anonymous>
> stack$push(10)
tracemem[0xb96450 -> 0x1b2a7d0]: <Anonymous> <Anonymous>
> stack
Class: Stack
current size: 2
maximum size: 100
head:
[1] 10
> while (!is.null(val <- stack$pop()))
+ cat("val:", val, "\n")
val: 10
val: 10
>
> https://stat.ethz.ch/pipermail/r-help/2010-March/230353.html (slightly edited)
>> [Subject:] [R] Stack type
>> [From:] Gabor Grothendieck ggrothendieck at gmail.com
>> [Date:] Tue Mar 2 14:33:43 CET 2010
>
>> library(proto)
>> Stack<- proto(new = function(.) proto(Stack,
>> stack = NULL,
>> push = function(., el) { .$stack<- c(list(el), .$stack) },
>> pop = function(.) {
> stopifnot(length(.$stack)> 0)
>> out<- .$stack[[1]]
>> .$stack[[1]]<- NULL
>> out
>> }))
>
>> mystack<- Stack$new()
>> mystack$push( 1 )
>> mystack$push( letters )
>> mystack$pop()
>> mystack$pop()
>> mystack$pop() # gives an error
>
> Thanks again! Tom Roche<Tom_Roche at pobox.com>
>
> ______________________________________________
> R-help at r-project.org mailing list
> https://stat.ethz.ch/mailman/listinfo/r-help
> PLEASE do read the posting guide http://www.R-project.org/posting-guide.html
> and provide commented, minimal, self-contained, reproducible code.
--
Computational Biology
Fred Hutchinson Cancer Research Center
1100 Fairview Ave. N. PO Box 19024 Seattle, WA 98109
Location: M1-B861
Telephone: 206 667-2793
More information about the R-help
mailing list