Justin In Oz
Justin In Oz

Reputation: 310

Eliminate for-loop through functional programming

I would like to take input from a dataframe with a systemName variable and a popNum variable and use this to generate a named list of vectors whose elements are the random numbers (1-6)*5 ie (5, 10, 15, 20, 25, 30) where the vector length is equal to the popNum of the system.

The following code works:

## Data
#Create a vector of integers
popNum <- c (2,5,3,9)
#Create corresponding names
systemNames <- c("Ruie", "Regina", "Roupe", "Efate")
# form up into a recatangular data frame
dataSource <- cbind.data.frame(systemNames,popNum )

## Create and Fill the List
#initialise the list
availableCargoes <- vector( mode = "list", length = nrow(dataSource))

#name the list
names(availableCargoes) <- dataSource$systemNames

#fill the list 
for (loopCounter in 1:nrow(dataSource)) {
availableCargoes[[loopCounter]] <- sample.int( n = 6, 
                                             size = dataSource$popNum[loopCounter],
                                             replace = TRUE) * 5
}

How can I get rid of the for-loop through something from the apply family or the purrr package? The problem I am having a hard time resolving is what is the X that the lapply runs the sample.int over? How do I pass the vector of popNum as an argument to control the size of the resulting vectors?

Upvotes: 1

Views: 97

Answers (2)

Mario Fajardo
Mario Fajardo

Reputation: 640

sapply version

## Data
#Create a vector of integers
popNum <- c (2,5,3,9)
#Create corresponding names
systemNames <- c("Ruie", "Regina", "Roupe", "Efate")
# form up into a recatangular data frame
dataSource <- cbind.data.frame(systemNames,popNum )

## Create and Fill the List
#initialise the list
availableCargoes <- vector( mode = "list", length = nrow(dataSource))

#name the list
names(availableCargoes) <- dataSource$systemNames

#fill the list 

availableCargoes <- sapply(as.character(dataSource$systemNames),function(sysname){

  sample.int( n = 6, 
              size = dataSource$popNum[dataSource$systemNames==sysname],
              replace = TRUE) * 5
},USE.NAMES=T,simplify = F)

Upvotes: 1

Rui Barradas
Rui Barradas

Reputation: 76653

Use lapply to loop directly through dataSource$popNum.
Note that I set the RNG seed to make the results reproducible.

set.seed(1234)
for (loopCounter in 1:nrow(dataSource)) {
  availableCargoes[[loopCounter]] <- sample.int( n = 6, 
                                                 size = dataSource$popNum[loopCounter],
                                                 replace = TRUE) * 5
}

set.seed(1234)
ac <- lapply(dataSource$popNum, function(s) 
  sample.int(n = 6, size = s, replace = TRUE)*5)
names(ac) <- dataSource$systemNames
ac

identical(availableCargoes, ac)
#[1] TRUE

Upvotes: 1

Related Questions