On Thu, Nov 15, 2012 at 5:48 PM, Benjamin Ward (ENV) <b.w...@uea.ac.uk> wrote: > Hi, > > I have some values in a list format generated by the following: > Path_Number <- 0010 > ID.Path <- formatC(0001:Path_Number, width=4, flag=0) # Make vector of ID's. > No_of_Effectors <- sample(1:550, length(ID.Path), replace=TRUE) # Define > Number of Effectors each individual gets. > Effectors <- split(sample(1:10000, sum(No_of_Effectors), replace=TRUE), > rep(ID.Path, No_of_Effectors)) # Generate effectors and dish them out. > Effectors > > And I've written a chunk which is designed to go through each element of the > list, and then through each value in the element, and if a conditions is met > (in this case if runif(1) is < 0.3, this is simple but may be changed later > to be more complex probability criteria based on mutation data from > experiment), change the value by 1 in either direction, higher or lower with > equal probability. Here it is (I've changed the 0.3 value I mentioned to 0.9, > so many values change so it can be easily seen): > > l<-0 # Set counter 1 to 0. > for(i in Effectors){ # Begin loop on list of effectors. > l2<-0 # Set counter 2 to 0. > l <-l+1 # Increace counter number 1. > for(i in Effectors[[l]]){ # Begin loop through all effector values. > l2 <-l2+1 # Increace counter number 2. > if(runif(1) < 0.9) ifelse(runif(1) <0.5, Effectors[[l]][l2] <- > Effectors[[l]][l2]+1, Effectors[[l]][l2] <- Effectors[[l]][l2]-1) # Line > which increaces or decreaces the values in the list element (50/50 chance of > increace or decreace), if the first IF statement is satisfied. > } > } > > Now I don't know if this is the best and most R-ish way of doing this, but it > works and I understand it. However I'd like to define a function with this, > my attempts so far have been: > > Eff.Mutate<-function(){ > l<-0 # Set counter 1 to 0. > for(i in Effectors){ # Begin loop on list of effectors. > l2<-0 # Set counter 2 to 0. > l <-l+1 # Increace counter number 1. > for(i in Effectors[[l]]){ # Begin loop through all effector values. > l2 <-l2+1 # Increace counter number 2. > if(runif(1) < 0.9) ifelse(runif(1) <0.5, Effectors[[l]][l2] <- > Effectors[[l]][l2]+1, Effectors[[l]][l2] <- Effectors[[l]][l2]-1) # Line > which increaces or decreaces the values in effvec, if the first IF statement > is satisfied. > } > } > } > > and: > > Eff.Mutate2<-function(x){ > l<-0 > for(i in x){ > l2<-0 > l<-l+1 > for(i in x[[l]]){ > l2<-l2+1 > if(runif(1) < 0.9) ifelse(runif(1) <0.5, x[[l]][l2] <- x[[l]][l2]+1, > x[[l]][l2] <- x[[l]][l2]-1) > } > } > } > > However if I do either Eff.Mutate() or Eff.Mutate2(Effectors), then neither > seems to work; I've seen no differences in the values in the list elements, > before and after. > I can't figure out why it works as a code chunk but if I try to make it a > function nothing seems to happen. I'm probably going about making it a > function wrong. >
The problem is that R functions do not operate on objects in the global environment, where your list lives. They make a copy and operate on that copy; when the function exists, that local copy is discarded. Here's a very simple example: # Function to change a change.a.wrong = function(new.a) { a = new.a; print(paste("Changed value of a to", a)) } #Initialize a to 1 a = 1 # change it to 5 change.a.wrong(5) # but a is still 1! a [1] 1 The local copy of a is changed to 5, but discarded and the global copy whose value is still 1 lives on. The solution is to return the value of the variable you have changed, and assign it to the original name. In your case you would define a function Eff.Mutate = function(x) { ...your code changes x return(x) } and you would call it as effectors.new = Eff.Mutate(effectors) or so. HTH, Peter ______________________________________________ R-help@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.