# Secret Santa in R

**R on Tea & Stats**, and kindly contributed to R-bloggers]. (You can report issue about the content on this page here)

Want to share your content on R-bloggers? click here if you have a blog, or here if you don't.

Our office just exchanged presents for *Secret Santa*, a tradition where each person is randomly assigned someone else to give an anonyous gift. One of the challenges of Secret Santa is keeping the pairs of gift-givers and receivers both random and secret. How can you do this while also taking part yourself? Using R, of course!

Firstly, recruit people! Write their names down, one per line, in a text file. The order doesn’t matter. For example, we might have a file called `santa_names.txt`

, with contents as follows:

Tom Dick Harry Jane Leslie Susan Alex Sam Chris

Then read these names into R.

names <- readLines('santa_names.txt')

We now have a character vector called `names`

.

The key to a truly random pairing of gift givers and recipients is that it shouldn’t depend on any systematic order, such as the order people signed up, or the alphabetical order of their names.

Here is one way we might try to do it. First, randomly reorder the `names`

. Then, have every person in this list give to the next person on the list, with the very last person then giving to the first.

names2 <- sample(names) data.frame(sender = names2, recipient = c(tail(names2, -1), names2[1])) ## sender recipient ## 1 Leslie Alex ## 2 Alex Susan ## 3 Susan Sam ## 4 Sam Tom ## 5 Tom Chris ## 6 Chris Jane ## 7 Jane Dick ## 8 Dick Harry ## 9 Harry Leslie

In R, the `sample()`

function draws randomly from a vector, and by default it does this without replacement, so we don’t have to worry about missing anybody off or somebody appearing twice. We can use it as a quick way to reorder the list of names at random. The `tail`

command with argument `-1`

will select every element in the list except the first.

This works in the sense that everybody gives and receives one gift and nobody gives to themselves, but is not entirely random or secret. If you find out that Susan gave to Leslie, then you know for a fact that Leslie didn’t give to Susan. With enough of these titbits of information you could reconstruct the entire list. Ideally we want no discernable pattern.

Why not just randomly sample twice from the `names`

list?

data.frame(sender = sample(names), recipient = sample(names)) ## sender recipient ## 1 Chris Dick ## 2 Jane Harry ## 3 Alex Sam ## 4 Tom Tom ## 5 Dick Leslie ## 6 Susan Susan ## 7 Harry Chris ## 8 Sam Alex ## 9 Leslie Jane

There’s a problem. Jane has been assigned to herself! That won’t do! The solution is quite straightforward, though: just keep sampling until this doesn’t happen. We can keep the order of senders fixed and vary the order of the recipients until nobody gives to themselves, like so.

sender <- sample(names) recipient <- sample(names) i <- 1 while (any(sender == recipient)) { i <- i + 1 recipient <- sample(names) } data.frame(sender, recipient) ## sender recipient ## 1 Chris Alex ## 2 Jane Tom ## 3 Alex Chris ## 4 Tom Leslie ## 5 Dick Susan ## 6 Susan Sam ## 7 Harry Jane ## 8 Sam Dick ## 9 Leslie Harry

Success! Everybody gives and receives a gift, nobody gives to themselves and there is no particular pattern. (Unlike the first method, Sam gives to Leslie even though Leslie already gives to Sam.)

If you’re curious, you can find out how many attempts it took to find a valid set of pairs:

i ## [1] 2

Now, how do you let everybody know who they have been assigned, without revealing it anybody else? (Including you!) We can write a text file for every person, with the name of the file corresponding to the giver and the contents of the file revealing the recipient.

for (i in seq_along(names)) { writeLines(recipient[i], paste0(sender[i], '.txt')) }

If you were feeling really clever, you could automate the e-mail sending from R as well, but it should be easy enough to attach and send the files by hand without peeking.

Putting it all together:

names <- readLines('santa_names.txt') sender <- sample(names) recipient <- sample(names) while (any(sender == recipient)) { recipient <- sample(names) } for (i in seq_along(names)) { writeLines(recipient[i], paste0(sender[i], '.txt')) }

**Merry Christmas!**

**leave a comment**for the author, please follow the link and comment on their blog:

**R on Tea & Stats**.

R-bloggers.com offers

**daily e-mail updates**about R news and tutorials about learning R and many other topics. Click here if you're looking to post or find an R/data-science job.

Want to share your content on R-bloggers? click here if you have a blog, or here if you don't.