Кто-то пытался сэкономить место и использовал кодирование битового поля в одном байте для хранения дней недели. Очевидно, они хотели показать, что они умные или обменять циклы ЦП на хранение.
Мы можем использовать функцию intToBits()
, чтобы получить числовое значение и преобразовать его в битовый массив.
Например:
intToBits(1)
## [1] 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
## [24] 00 00 00 00 00 00 00 00 00
intToBits(4)
## [1] 00 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
## [24] 00 00 00 00 00 00 00 00 00
intToBits(5)
## [1] 01 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
## [24] 00 00 00 00 00 00 00 00 00
По какой-то причине PoweRs That Be ™ предпочли поставить наименее значимую цифру первой (возможно, из-за приема ЛСД). Он также получил way слишком много битов для нас, так как нам просто нужно 7.
Итак, нам просто нужно что-то переставить и сжать при кодировании и декодировании:
decode_days <- function(x) {
days <- c("Sunday", "Saturday", "Friday", "Thursday", "Wednesday", "Tuesday", "Monday")
lapply(x, function(y) {
rev(days[as.logical(rev(intToBits(y)[1:7]))])
})
}
encode_days <- function(x) {
c(
"sunday" = 64, "saturday" = 32, "friday" = 16, "thursday" = 8,
"wednesday" = 4, "tuesday" = 2, "monday" = 1
) -> days
sapply(x, function(y) {
y <- unique(tolower(trimws(y)))
y <- y[y %in% names(days)]
sum(days[y])
})
}
Расшифровка в действии:
decode_days(c(1,2,4,8,16,32,64,127,21))
## [[1]]
## [1] "Monday"
##
## [[2]]
## [1] "Tuesday"
##
## [[3]]
## [1] "Wednesday"
##
## [[4]]
## [1] "Thursday"
##
## [[5]]
## [1] "Friday"
##
## [[6]]
## [1] "Saturday"
##
## [[7]]
## [1] "Sunday"
##
## [[8]]
## [1] "Monday" "Tuesday" "Wednesday" "Thursday" "Friday" "Saturday"
## [7] "Sunday"
##
## [[9]]
## [1] "Monday" "Wednesday" "Friday"
Кодировка в действии:
encode_days(decode_days(c(1,2,4,8,16,32,64,127,21)))
## [1] 1 2 4 8 16 32 64 127 21
Кодер можно немного оптимизировать, но это упражнение осталось для OP, поскольку я попытался реализовать «для того, чтобы сделать перевод более наглядным».
FWIW Таблица поиска для кодирования / декодирования (как вы предложили) намного быстрее, чем этот метод (просто показывает частичный пример декодирования):
list(
"1" = "Monday",
"2" = "Tuesday",
"3" = c("Monday", "Tuesday"),
"4" = "Wednesday",
"5" = c("Monday", "Wednesday"),
"6" = c("Tuesday", "Wednesday"),
"7" = c("Monday", "Tuesday", "Wedneday"),
"8" = "Thursday"
# you can do the rest
) -> decode_lkp
# moved this outside to make it a fair comparison
days_dec <- rev(c("Sunday", "Saturday", "Friday", "Thursday", "Wednesday", "Tuesday", "Monday"))
decode_days <- function(x) { # optimized version
lapply(x, function(y) {
days_dec[as.logical(intToBits(y)[1:7])]
})
}
microbenchmark::microbenchmark(
lookup = unname(decode_lkp[c(1:8)]),
`ƒ()` = decode_days(1:8)
)
## Unit: microseconds
## expr min lq mean median uq max neval
## lookup 1.599 1.7635 2.13525 1.843 1.944 25.302 100
## ƒ() 12.126 12.8310 40.92872 13.084 13.447 2741.986 100
но я подумал, что это поможет показать "логику", стоящую за попытками ваших предшественников на хитрость, а кодировка имеет некоторую пуленепробиваемость.
Для «как» с б / т / т бит / дюйм, байт составляет 8 бит, но здесь они используют только 7, поэтому мы будем придерживаться 7.
64 32 16 08 04 02 01
Если мы установим все биты в 0, кроме 01
:
64 32 16 08 04 02 01
0 0 0 0 0 0 1
У нас есть этот день недели. Если мы установим 04
и 01
, мы
64 32 16 08 04 02 01
0 0 0 0 1 0 1
У нас есть эти двое. Везде, где есть 1
, мы добавляем заголовок #.
В других языках можно использовать бинарные операторы для проверки и установки битов. Это в некотором роде возможно в R, но в большинстве случаев это проще.