Home > Enterprise >  R: Randomly Selecting Items from a List
R: Randomly Selecting Items from a List

Time:09-24

I am working with the R programming language. I want to create a problem in which:

  • There are 4 people : "person 1", "person 2", "person 3" ,"person 4"

  • There is a list of food items: "pizza", "apples", "tacos", "ice cream", "grapes", "olives", "sushi", "chocolate", "cake", "nachos", "pasta", "cookies", "popcorn", "soup"

  • There is a list of days in the year: 1 to 365

In this problem, the list of people is randomly sorted. The order of this list decides who get to "pick first".

According to the order of the list, the person at the start of the list will be assigned 4 random numbers:

  • Rand_1_1 (Person 1, First Random Number) : The first random number will decide the number of "food items" the first person is allowed to pick (e.g. 3)

  • Rand_1_2 (Person 1, Second Random Number) : The second random number will decide which "food items" the first person will pick with the number of "food items" corresponding to "Rand_1_1" (e.g. "tacos", "nachos", "soup")

  • Rand_1_3 (Person 1, Third Random Number): The third random number will decide the one of the bound for the days for the first person

  • Rand_1_4 (Person 1, Fourth Random Number): The fourth random number will decide the other bound for the days for the first person (e.g. Person 1 might be assigned days "41 to 160").

This is random number assignment process is then completed for all people : Rand_1_1, Rand_1_2, Rand_1_3, Rand_1_4 , Rand_2_1, Rand_2_2, Rand_2_3, Rand_2_4, Rand_3_1, Rand_3_2, Rand_3_3, Rand_3_4, Rand_4_1, Rand_4_2, Rand_4_3, Rand_4_4

However, there is one logical constraint:

  • A "person" can not choose "food items" that have already been chosen by the "person" before them (e.g. if Person 1 was selected to choose before Person 2, and if Person 1 chose "pizza" then Person 2 can not choose "pizza")

  • A "person" can not choose a "range of days" that has already been chosen by the "person" before them

  • After all 4 people have finished choosing, it is possible that some "food items" and some "date ranges" can remain unselected. On the other hand, suppose if Person 1 chooses first and he happens to select all the "food items" - then of course, the other people will have no "food items". The same logic applies for "date ranges".

Now, I am trying to code this in R:

First, I loaded the libraries:

#load libraries

library(dplyr)
library(gtools)

Second, I created the data:

#create data

#variable 1: days of the year 

days <- 1:365

#variable 2 : food

food <- c("pizza", "apples", "tacos", "ice cream", "grapes", "olives", "sushi", "chocolate", "cake", "nachos", "pasta", "cookies", "popcorn", "soup")
food_data <- data.frame(food)
food_data$id <-  1:nrow(food_data)

# people 
people <- c("person 1", "person 2", "person 3" ,"person 4")

Third, I created the order in which the people will pick:

# randomize order of people : this decides the order of who picks "days" and "food"

set.seed(123)

order_of_people = permute(people)

# in this example, "person 3" will pick first, "person 4" will pick second, "person 1" will pick third and "person 2" will pick last

order_of_people
[1] "person 3" "person 4" "person 1" "person 2"

My Problem: I know how to assign every person a random number, but I do not know how to assign the random numbers such that the logical constraints are respected. For example:

#choices for person 3 (according to the random seed, person 3 will pick 5 food items)

set.seed(120)

dim = dim(food_data)

#number of items selected by person 3

Rand_3_1 <- sample.int(dim[1], 1)

#which food items selected by person 3 (corresponding to the food_id : "3, 9, 6, 7, 4")
set.seed(120)

Rand_3_2 = c( sample.int(dim[1], 1), sample.int(dim[1], 1), sample.int(dim[1], 1),  sample.int(dim[1], 1), sample.int(dim[1], 1))

#which days selected by person 3 (according to this random seed, "65 to 87")

set.seed(120)

Rand_3_3 <- sample.int(365, 1)
Rand_3_4 <- sample.int(365, 1)

Thus, I can create "selection frames" for each person:

#Person 1
Rand_1_1 <- sample.int(dim[1], 1)

Rand_1_2 = c( #fill randomly with amount of items specified by Rand_1_1)

Rand_1_3 <- sample.int(365, 1)
Rand_1_4 <- sample.int(365, 1)

#Person 2
Rand_2_1 <- sample.int(dim[1], 1)

Rand_2_2 = c( #fill randomly with amount of items specified by Rand_2_1)

Rand_2_3 <- sample.int(365, 1)
Rand_2_4 <- sample.int(365, 1)


#Person 3
Rand_3_1 <- sample.int(dim[1], 1)

Rand_3_2 = c( #fill randomly with amount of items specified by Rand_3_1)

Rand_3_3 <- sample.int(365, 1)
Rand_3_4 <- sample.int(365, 1)

#Person 4
Rand_4_1 <- sample.int(dim[1], 1)

Rand_4_2 = c( #fill randomly with amount of items specified by Rand_4_1)

Rand_4_3 <- sample.int(365, 1)
Rand_4_4 <- sample.int(365, 1)

But I don't know how to do this such that the logical constraints are respected. In the end, I am trying to produce something like this:

#desired results
Person 1 : "apples, tacos" and "4-51"
Person 2: "cookies, nachos, cake, olives", and "56-180"
Person 3: "ice cream", and "200-214"
Person 4: "sushi, popcorn" and "350-365"

Can someone please show me how to do this?

Thanks

CodePudding user response:

It seems straight-forward unless I am missing something, you have a list of foods and days, so just keep track of the available options each time you run through a person and only select from those options:

## initialize the inputs
set.seed(1)
foods <- letters[1:20]
nfoods <- sample(5, 4)
tmp <- list(unpicked = list(food = foods, days = 1:365))

## run it
tmp <- lapply(nfoods, function(x) tmp <<- f(tmp$unpicked$food, x, tmp$unpicked$days))

## summarize it
res <- sapply(seq_along(tmp), function(ii) {
  x <- tmp[[ii]]
  x <- sprintf('person %s: "%s" and "%s"', ii, toString(x$picked$food),
               paste0(x$picked$days, collapse = '-'))
  cat(x, sep = '\n')
  invisible(x)
})
# person 1: "b" and "270-299"
# person 2: "s, a, k, g" and "306-336"
# person 3: "m, t, h" and "42-89"
# person 4: "j, f, q, o, l" and "129-210"


f <- function(food, n, days) {
  # f(1:4, 3, 1:10)
  food1 <- sample(food, n)
  
  days1 <- split(days, cumsum(is.na(days)))
  days1 <- sample(Filter(function(x) length(x) > 2, days1), 1)[[1]]
  days1 <- sort(sample(sort(days1), 2))
  
  days[do.call('seq', as.list(days1))] <- NA
  
  list(
    picked = list(food = food1, days = days1),
    unpicked = list(food = setdiff(food, food1), days = days)
  )
}
  • Related