My Aim:

I'd like to a have a function that takes an email address and outputs a quasi-random number of 1, 2, 3, or 4.

A little detail:

By quasi-random number I mean that given a typical population of email addresses, the probabilities of getting a value of 1, 2, 3, or 4 are roughly equal, and that obvious systematic properties of the email address such as the domain name do not affect the probability of getting a value of 1, 2, 3, or 4.

A little background:

I have an online experiment written in inquisit where participants log in on two occasions. I want to randomly assign participants to one of four groups. While this is easy to do for one session (I can just use a random number generator), I need some way of remembering the allocation across sessions. Thus, I thought that I could extract a quasi-random group allocation from the participant email. I'm also limited in the set of functions that I have at my disposal (see here for full list). The string functions are: tolower toupper capitalize concat search replaceall contains startswith endswith substring trim trimright trimleft length format evaluate

Initial Thoughts:

I thought about trying to extract a set of features of the email address that returned a value of 1, 2, 3, or 4 with roughly equal probabilities. Then, I could sum these properties and get the mod 4 plus 1 of that. Thus, assuming something like the central limit theorem, I might get close.

Possible features that came to my mind:

  • length of string
  • position of first "a", "b", etc.
  • 1
    $\begingroup$ A very interesting problem. Do you have a sample of "typical population of email addresses" at hand ? Additionally it is not guaranteed, that the email-addresses of the visitors do have the same another/different structure, but since you are only looking for an approximation.... Second question: Are you able to set the seed of the RNG ? $\endgroup$
    – mlwida
    Feb 16, 2011 at 9:26
  • 6
    $\begingroup$ Sounds like you want a 'hash function': en.wikipedia.org/wiki/Hash_function This is in the realms of computer science rather than statistics though, so I'm not sure it belongs on CrossValidated. $\endgroup$
    – onestop
    Feb 16, 2011 at 10:20
  • 1
    $\begingroup$ hmpf ;) ... I intended to write the same. @Jeromy: Especially this part of the site (en.wikipedia.org/wiki/…) could be interesting for you. $\endgroup$
    – mlwida
    Feb 16, 2011 at 10:51
  • $\begingroup$ @onestop Thanks for the tip about hashtags. With regards to whether the question is on topic for the site, I think random allocation of participants to groups is inherently related to study design, which in turn is related to inferences from data. $\endgroup$ Feb 16, 2011 at 14:20
  • 1
    $\begingroup$ @Jeremy A hash function is not the same thing at all as a hashtag! I see your point about study design though. I admit to not reading the whole of your question properly. $\endgroup$
    – onestop
    Feb 16, 2011 at 14:27

4 Answers 4


Look up hash functions, for example at http://en.wikipedia.org/wiki/Hash_function


Why not just have a look-up table of numbers for each possible character in an email. Then concatenate the numbers to form a seed. For example,

A 1
B 2
C 3
@ 27

So abc@ccc, would be converted to 12327333. This would give you a unique seed for each person. You would then use this to generate the 1, 2, 3, 4.

From your question, it looks like you don't mind a "quick and dirty solution". One problem with my solution is that email addresses aren't random - for example you will probably get very few email addresses that contain the letter "z", but all email addresses contain "@".

  • $\begingroup$ A minor note about the above method is that there are a bunch of valid characters in email addresses - punctuation in particular - that you would want to consider if you were doing this. $\endgroup$
    – dsolimano
    Feb 16, 2011 at 14:51
  • $\begingroup$ @dsol: I agree. You could easily be caught out with a "+" in an email address. For a quick and dirty solution, I would probably just skip any punctuation characters that I hadn't specified in my look-up table. $\endgroup$ Feb 16, 2011 at 14:59

As an addition to other excellent answers, I just will give a simple example in R language to show a very simple hash function, which should be good enough for this purpose. To get some email addresses as test data, I get a character vector with the emails of the maintainers of the (too many!) R packages installed on my computer:

library(stringr) # on CRAN 
last <- function(x) { return( x[length(x)] ) }

INST  <-  installed.packages(priority="NA", fields=c("Maintainer"))
Maintainer <- INST[, "Maintainer"]
Mlist <- str_split(Maintainer, "[[:blank:]]")
Maddr <- sapply(Mlist, FUN=last)
Maddr <- str_replace(Maddr, "[<>]", "")
Maddr <- unique(Maddr)

Then I define a simple function which gets some number from each character in the email address, adds them, computes the remainder modulo 4 and adds 1, so it returns always one of the results 1,2,3 or 4:

apply_to_each_char  <-  function(w, FUN) {
    ww <-  str_split(w, "")[[1]]
    res <- sapply(ww, FUN)
    } # END apply_to_each_char
charsum <- function(word) { # length-one char vector
    sum0 <- sum( apply_to_each_char(word, function(w) as.integer(charToRaw(w)) ))
    return( 1 + sum0 %% 4)
    } # end charsum

Then applying it:

hashes <- sapply(Maddr, charsum)
  1   2   3   4 
542 511 562 552 

and we can observe that the resulting distribution is close to uniform.


You could try converting each character to an ascii number, multiplying them all together to force overflow, and then performing a modulus operation on the least significant digits. If this is not pseudo-random enough, you can perform a bit-shift the numbers a bit...

-Ralph Winters

  • 2
    $\begingroup$ Multiplying is not the best idea, I think. Especially if your initial overflow is the regular one - modulo some power of 2. You will get a lot of factors that are even, so most of your lower bits will be 0. Adding the numbers together instead would already be a lot better. If you need even better randomness, use some sort of hash function and use any bits of the result. If you want it to be difficult to guess anything about the outcome for people other than you, use a salted strong cryptographic hash function. $\endgroup$
    – Erik P.
    Feb 16, 2011 at 17:17
  • $\begingroup$ Agreed. Just wanted to suggest idea to illustrate bit shifting in order to generate (roughly) pseudo-random numbers. $\endgroup$ Feb 17, 2011 at 18:48

Not the answer you're looking for? Browse other questions tagged or ask your own question.