Please find a quick solution below. Here, simply cycling carefully through the group of users is fine.
In the solution below, all groups have always at least 6 people served per day. More specifically we always serve either 7 or 8 people per group for Days 1 to 3; in Day 4 might have a group $i$ with "only" 6 people served due to random variation of group $i$ having repeatedly 8 people served in the Days 1 to 3; in Day 5 we once again have at least 7.
The code is commented extensively but let me know if you want any clarifications.
The main thing is to remember the pigeonhole principle when working through the steps - it essentially what makes this work at Day 4. Otherwise Days 1 to 3 are "usual" stratified random sampling - the stratification being done on the team/group level.
# Setting up the data.frame to hold the results
set.seed(3)
people <- expand.grid(letters[1:20], 1:10)
colnames(people) <- c('group','index')
people$uid <- apply(people,1, function(x) paste0("", x[1], x[2]))
# Day 1:
# Pick the first 7 people from each group (7 * 20 = 140)
people$day1 <- people$index %in% 1:7 #change to sample(size=7,x=10) for something more random
# Pick the remain 10 at random from the ones not selected but only additional one from each group!
for (my_group in sample(unique(people$group), size = 10, replace = FALSE)){
grp_indx <- which( (FALSE == people$day1) & (my_group == people$group))
people$day1[ sample(grp_indx,replace = FALSE, size =1)] = TRUE
}
# Day 2:
# Pick the 50 people not selected in Day 1
people$day2 <- !people$day1
# Pick the remain 100 at random from the ones not selected in the previous step (i.e. the ones who were served in Day 1)
# We do this in two steps
# Step 1: We sample in a stratified manner by group to ensure we never have a group with less than 7 served on Day 2 either
for (my_group in unique(people$group)){
grp_indx <- which( (FALSE == people$day2) & (my_group == people$group))
people$day2[ sample(grp_indx,replace = FALSE, size = length(grp_indx) - (10-7)) ] = TRUE
}
# Step 2: Pick the remain 10 at random from the ones not selected but only additional one from each group!
for (my_group in sample(unique(people$group), size = 10, replace = FALSE)){
grp_indx <- which( (FALSE == people$day2) & (my_group == people$group))
people$day2[ sample(grp_indx,replace = FALSE, size =1)] = TRUE
}
# Day 3:
# Pick the 100 people who were not selected in both Day 1 & 2 already (ensuring everyone get at least two servings by day 3)
people$day3 <- !(people$day1 & people$day2)
# Pick the remain 50 at random from the ones not selected in the previous step (i.e. the ones who were served in Day 1 &2)
# We do this in two steps
# Step 1: We sample in a stratified manner by group to ensure we never have a group with less than 7 served on Day 3 either
for (my_group in unique(people$group)){
grp_indx <- which( (FALSE == people$day3) & (my_group == people$group))
people$day3[ sample(grp_indx,replace = FALSE, size = length(grp_indx) - (10-7)) ] = TRUE
}
# Step 2: Pick the remain 10 at random from the ones not selected but only one per group!
for (my_group in sample(unique(people$group), size = 10, replace = FALSE)){
grp_indx <- which( (FALSE == people$day3) & (my_group == people$group))
people$day3[ sample(grp_indx,replace = FALSE, size =1)] = TRUE
}
# Day 4:
# Pick the people who were not already served three times
people$day4 <- !(people$day1 + people$day2+ people$day3 == 3)
# At this point everyone has been selected exacty three times
all(rowSums(people[,c('day1','day2','day3','day4')]) == 3)
# Day 5: # Repeat Day 1 effectively
# Pick the first 7 people from each group (7 * 20 = 140)
people$day5 <- people$index %in% sample(size=7,x=10) # something more random than just the first 7 people per group
# Pick the remain 10 at random from the ones not selected / we don't care to stratify at this point really
people$day5[sample(which(FALSE == people$day5), size = 10, replace = FALSE)] = TRUE