library(magrittr)

## Version 1 (Pipes)

# Convert a vector of integer to vector of strings of n binary digits
old_old_int_to_n_bits <- function(xs, n = 16, start = 1) {
  vapply(xs, old_old_int_to_n_bits_one, FUN.VALUE = character(1),
         n = n, start = start, USE.NAMES = FALSE)
}

# Convert an integer to a string of n binary digits
old_old_int_to_n_bits_one <- function(x, n = 16, start = 1) {
  sequence <- seq(n, start, by = -1)
  bits <- x %>% intToBits() %>% as.integer()
  bits[sequence] %>% paste0(collapse = "")
}


## Version 2 (No pipes)

# Improvement of slower version
old_int_to_n_bits <- function(xs, n = 16, start = 1) {
  vapply(xs, old_int_to_n_bits_one, FUN.VALUE = character(1),
         n = n, start = start, USE.NAMES = FALSE)
}

# Convert an integer to a string of n binary digits
old_int_to_n_bits_one <- function(x, n = 16, start = 1) {
  # I used pipes here before but those had a huge hit on performance for the
  # problem with 40,000,000 numbers to compare
  sequence <- seq(n, start, by = -1)
  bits <- as.integer(intToBits(x))
  paste0(bits[sequence], collapse = "")
}




## Version 3 (Convert numbers en masse)

int_to_n_bits <- function(xs, n = 16, start = 1) {
  indices <- seq_len(length(xs))
  # intToBits(xs) returns 32 bits for each number of xs and each bit has a
  # leading zero like 01 00 00 00. The item on the left is the smallest digit.
  #
  # as.integer() will remove the leading zeros.
  #
  # The rep() lines produces 1 repeated 32 times followed by 2 repeated 32
  # times, etc. Splitting on these values will get us a list where each element
  # in the list has the binary digits for each number.
  bits <- split(as.integer(intToBits(xs)), rep(indices, each = 32))

  # Here we convert the vectors of binary digits into strings. Using `n:start`
  # will reverse the digits so the smallest digit is on the right.
  vapply(bits, function(x) paste0(x[n:start], collapse = ""),
         character(1), USE.NAMES = FALSE)
}



xs <- 1:1000L

microbenchmark::microbenchmark(
  version1 = old_old_int_to_n_bits(xs),
  version2 = old_int_to_n_bits(xs),
  version3 = int_to_n_bits(xs),
  times = 100L)
## Unit: milliseconds
##      expr       min        lq      mean    median        uq       max
##  version1 336.42408 339.12989 344.52020 340.79864 342.52616 405.86759
##  version2  38.84024  39.63414  40.30618  40.20242  40.68446  45.44770
##  version3  11.92375  12.09872  12.47795  12.22601  12.52894  19.09137
##  neval cld
##    100   c
##    100  b 
##    100 a