The ids package provides randomly generated ids in a number of different forms with different readability and sizes.

Random bytes

The random_id function generates random identifiers by generating bytes random bytes and converting to hexadecimal (so each byte becomes a pair of characters). Rather than use R’s random number stream we use the openssl package here.

ids::random_id()
## [1] "af9faf84cc0cef6d143cc521a4191238"

All ids functions take n as the first argument to be the number of identifiers generated:

ids::random_id(5)
## [1] "91ce932e3fe6889ec6ea04cf7be97252" "3c3871e5c07704f362cf8322b937d7a3"
## [3] "5c0e6d1b94622d05e0fa6639b5a4b295" "73d7cbc1b8ebfec46869909152ac94a3"
## [5] "5a66b5aba773d96af2de7bbb0120791f"

The default here is 16 bytes, each of which has 256 values (so 256^16 = 2^128 = 3.4e38 combinations). You can make these larger or smaller with the bytes argument:

ids::random_id(5, 8)
## [1] "9f494c9a18bfb59c" "689aa1b6c86c9b79" "bd602f715871b5b1"
## [4] "dd5b3f69384aa415" "1dbc558231afd7b6"

If NULL is provided as n, then a generating function is returned (all ids functions do this):

f <- ids::random_id(NULL, 8)
f
## function (n = 1) 
## {
##     random_id(n, bytes, use_openssl)
## }
## <environment: 0x3ad5938>

This function sets all arguments except for n

f()
## [1] "18bc9be1fa50b776"
f(4)
## [1] "4bb61a62799cde62" "52fd6843ca5b4258" "25205704e70ab08c"
## [4] "fe0f594fee47a55d"

UUIDs

The above look a lot like UUIDs but they are not actually UUIDs. The uuid package provides real UUIDs generated with libuuid, and the ids::uuid function provides an interface to that:

ids::uuid()
## [1] "af144ea8-6c5e-4290-bc54-b9f67e6826c0"

As above, generate more than one UUID:

ids::uuid(4)
## [1] "c8f0b243-1102-45d6-83d7-fe9ed37235cb"
## [2] "b0afec65-727a-40e1-b219-c32703913c3e"
## [3] "a6bdcc68-e9c9-4b0f-af3c-d49d6ab89bb2"
## [4] "92c4c5f3-977c-4e58-9c97-754706467b7e"

Generate time-based UUIDs:

ids::uuid(4, use_time = TRUE)
## [1] "f1cff734-a287-11e6-b7e2-5065f32b99c0"
## [2] "f1cff7b6-a287-11e6-b7e2-5065f32b99c0"
## [3] "f1cff806-a287-11e6-b7e2-5065f32b99c0"
## [4] "f1cff892-a287-11e6-b7e2-5065f32b99c0"

and optionally drop the hyphens:

ids::uuid(5, drop_hyphens = TRUE)
## [1] "4af1d9bae17040299bbe9ab4d89bfdab" "17b1b80dbeef4bc299f16c8c28781f56"
## [3] "797db83da0d847ee9fcb0aa25e103069" "2f78106ec59840718474b549552f9071"
## [5] "6df0c9591d8749a194608e8ff9618aac"

Adjective animal

Generate (somewhat) human readable identifiers by combining one or more adjectives with an animal name.

ids::adjective_animal()
## [1] "previgilant_irishdraughthorse"

The list of adjectives and animals comes from gfycat.com, via https://github.com/a-type/adjective-adjective-animal

Generate more than one identifier:

ids::adjective_animal(4)
## [1] "moony_eidolonhelvum"       "monarchical_mosquito"     
## [3] "inadvertent_frilledlizard" "pennypinching_muskox"

Use more than one adjective for very long idenfiers

ids::adjective_animal(4, 3)
## [1] "hoggish_pseudoprophetic_illbehaved_tarantula"                  
## [2] "secretive_brassbound_cerebrospinal_pygmy"                      
## [3] "nickel_downcast_epimyocardial_wildcat"                         
## [4] "pseudoscholarly_deprivable_acidimetrical_woollybearcaterpillar"

There are 1750 animal names and 8946 adjectives so each one you add increases the idenfier space by a factor of 8946. So for 1, 2, and 3 adjectives there are about 15.7 million, 140 billion and 1250 trillion possible combinations.

This is a much smaller space than the random identifiers above, but these are more readable and memorable.

Note that here, the random nunbers are coming from R’s random number stream so are affected by set.seed().

Because some of the animal and adjective names are very long (e.g. a quasiextraterritorial hexakosioihexekontahexaphobic queenalexandrasbirdwingbutterfly), in order to generate more readable/memorable identifiers it may be useful to restrict the length. Pass max_len in to do this.

ids::adjective_animal(4, max_len = 6)
## [1] "bovid_elver"   "decent_yucker" "wieldy_gibbon" "ghast_burro"

A vector of length 2 here can be used to apply to the adjectives and animal respectively:

ids::adjective_animal(20, max_len = c(5, Inf))
##  [1] "lowly_beauceron"               "tin_newtnutria"               
##  [3] "good_towhee"                   "high_ray"                     
##  [5] "oozy_easternglasslizard"       "famed_peccary"                
##  [7] "diet_elephant"                 "aware_quoll"                  
##  [9] "acute_attwatersprairiechicken" "hated_uintagroundsquirrel"    
## [11] "shiny_xeme"                    "dirt_africanelephant"         
## [13] "front_walkingstick"            "tart_herculesbeetle"          
## [15] "rear_galapagospenguin"         "twill_crane"                  
## [17] "nude_grayreefshark"            "stuck_genet"                  
## [19] "catty_unau"                    "smoky_irukandjijellyfish"

Note that this decreases the pool size and so increases the chance of collisions.

In addition to snake_case, the default, the punctuation between words can be changed to:

kebab-case:

ids::adjective_animal(1, 2, style = "kebab")
## [1] "nimble-winterhardy-goose"

dot.case:

ids::adjective_animal(1, 2, style = "dot")
## [1] "previgilant.proscience.archerfish"

camel-case:

ids::adjective_animal(1, 2, style = "camel")
## [1] "nostalgicNarcolepticSiamesecat"

PascalCase:

ids::adjective_animal(1, 2, style = "pascal")
## [1] "InorganicHoundishMouse"

CONSTANT_CASE (aka SHOUTY_CASE)

ids::adjective_animal(1, 2, style = "constant")
## [1] "EMBATTLED_VERMINOUS_ARCTICFOX"

or with spaces, lower case:

ids::adjective_animal(1, 2, style = "lower")
## [1] "metalline easeful meadowhawk"

UPPER CASE

ids::adjective_animal(1, 2, style = "upper")
## [1] "INCORRUPTIBLE SALINE HEIFER"

Sentence case

ids::adjective_animal(1, 2, style = "sentence")
## [1] "Openminded reanalyzable caribou"

Title Case

ids::adjective_animal(1, 2, style = "title")
## [1] "Inconvenient Kitschy Trout"

Again, pass n = NULL here to create a generating function:

aa3 <- ids::adjective_animal(NULL, 3, style = "kebab", max_len = c(6, 8))

…which can be used to generate ids on demand.

aa3()
## [1] "spooky-tanned-winged-ragfish"
aa3(4)
## [1] "bleak-witted-veiny-argali"  "red-diet-palish-drongo"    
## [3] "looney-linear-dark-gannet"  "immune-sphene-mucky-xenops"

Random sentences

The sentence function creates a sentence style identifier. This uses the approach described by Asana on their blog. This approach encodes 32 bits of information (so 2^32 ~= 4 billion possibilities) and in theory can be remapped to an integer if you really wanted to.

ids::sentence()
## [1] "25_mighty_elves_jogging_quickly"

As with adjective_animal, the case can be changed:

ids::sentence(2, "dot")
## [1] "23.finicky.salamanders.zooming.valiantly"
## [2] "8.bizarre.gazelles.traveling.gladly"

If you would rather past tense for the verbs, then pass past = TRUE:

ids::sentence(4, past = TRUE)
## [1] "33_astonishing_platypuses_squiggled_optimistically"
## [2] "16_sassy_llamas_gathered_quaintly"                 
## [3] "33_colossal_deers_charged_longingly"               
## [4] "15_waggish_turtles_charged_gently"

Roll your own identifiers

The ids functions can build identifiers in the style of adjective_animal or sentence. It takes as input a list of strings. This works particularly well with the rcorpora package which includes lists of strings.

Here is a list of Pokemon names:

pokemon <- tolower(rcorpora::corpora("games/pokemon")$pokemon$name)
length(pokemon)
## [1] 663

…and here is a list of adjectives

adjectives <- tolower(rcorpora::corpora("words/adjs")$adjs)
length(adjectives)
## [1] 962

So we have a total pool size of about 638 thousand, which is not huge, but it is at least topical.

To generate one identifier:

ids::ids(1, adjectives, pokemon)
## [1] "bruising_meowth"

All the style-changing code is available:

ids::ids(10, adjectives, pokemon, style = "dot")
##  [1] "timely.tranquill"     "left-footed.nincada"  "embryo.mudkip"       
##  [4] "natural.slugma"       "recognised.excadrill" "favourable.nidoran♂" 
##  [7] "foolhardy.roggenrola" "parental.hitmonchan"  "glorified.manectric" 
## [10] "supervisory.garchomp"

Better would be to wrap this so that the constants are not passed around the whole time:

adjective_pokemon <- function(n = 1, style = "snake") {
  pokemon <- tolower(rcorpora::corpora("games/pokemon")$pokemon$name)
  adjectives <- tolower(rcorpora::corpora("words/adjs")$adjs)
  ids::ids(n, adjectives, pokemon, style = style)
}

adjective_pokemon(10, "kebab")
##  [1] "glorified-oddish"      "bonnie-swinub"        
##  [3] "metering-minccino"     "muted-heatran"        
##  [5] "tudor-tyranitar"       "territorial-magnemite"
##  [7] "thicker-giratina"      "sunshine-blastoise"   
##  [9] "valiant-abra"          "disdainful-rotom"

As a second example we can use the word lists in rcorpora to generate identifiers in the form <mood>_<scientist>, like “melancholic_darwin”. These are similar to the names of docker containers.

First the lists of names themselves:

moods <- tolower(rcorpora::corpora("humans/moods")$moods)
scientists <- tolower(rcorpora::corpora("humans/scientists")$scientists)

Moods include:

sample(moods, 10)
##  [1] "satiric"     "glad"        "merry"       "listless"    "agitated"   
##  [6] "thrilled"    "annoyed"     "bold"        "replaced"    "heartbroken"

The scientists names contain spaces which is not going to work for us because ids won’t correctly translate all internal spaces to the requested style.

sample(scientists, 10)
##  [1] "lester r. brown"             "abdul qadeer khan"          
##  [3] "nicolaus copernicus"         "ernst mach"                 
##  [5] "katharine burr blodgett"     "b. f. skinner"              
##  [7] "pearl kendrick"              "christiane nusslein-volhard"
##  [9] "maria gaetana agnesi"        "ukichiro nakaya"

To hack around this we’ll just take the last name from the list and remove all hyphens:

scientists <- vapply(strsplit(sub("(-|jr\\.$)", "", scientists), " "),
                     tail, character(1), 1)

Which gives strings that are just letters (though there are a few non-ASCII characters here that may cause problems because string handling is just a big pile of awful)

sample(scientists, 10)
##  [1] "hahn"       "leoniceno"  "born"       "cajal"      "brown"     
##  [6] "heisenberg" "delbruck"   "schottky"   "buckland"   "copernicus"

With the word lists, create an identifier:

ids::ids(1, moods, scientists)
## [1] "attacked_marcet"

Or pass NULL for n and create a function:

sci_id <- ids::ids(NULL, moods, scientists, style = "kebab")

which takes just the number of identifiers to generate as an argument

sci_id(10)
##  [1] "inflated-babbage"    "pleased-thoreau"     "self-conscious-born"
##  [4] "daring-haxel"        "weary-bain"          "miserable-burnell"  
##  [7] "troubled-elion"      "troubled-dobzhansky" "giving-behring"     
## [10] "ridiculous-houssay"