R Language
해시 맵
수색…
해시 맵으로서의 환경
주 : 후속 구절에서 해시 맵 과 해시 테이블 이라는 용어는 같은 의미로 사용되며, 즉 내부 해시 함수를 사용하여 효율적인 키 검색을 제공하는 데이터 구조를 나타냅니다.
소개
R은 기본 해시 테이블 구조를 제공하지 않지만 new.env
에서 반환 된 environment
객체 (기본적으로)가 해시 된 키 조회를 제공한다는 사실을 이용하여 비슷한 기능을 구현할 수 있습니다. 다음 두 문은 동등합니다. hash
매개 변수의 기본값은 TRUE
.
H <- new.env(hash = TRUE)
H <- new.env()
또한, 내부 해시 테이블이 기본값 29를 갖는 size
매개 변수를 통해 특정 크기로 미리 할당되도록 지정할 수 있습니다. 다른 모든 R 개체와 마찬가지로 environment
은 자체 메모리를 관리하며 필요에 따라 용량이 커집니다 따라서 size
기본값이 아닌 값을 요청할 필요는 없지만 개체에 매우 많은 수의 요소가 포함될 경우 약간의 성능 이점이있을 수 있습니다. size
를 통해 여분의 공간을 할당해도 그 자체로 더 큰 메모리 공간을 가진 객체가 생성되지 않는다는 점에 주목할 필요가 있습니다.
object.size(new.env())
# 56 bytes
object.size(new.env(size = 10e4))
# 56 bytes
삽입
요소의 삽입을 사용하여 수행 할 수의 중 하나 [[<-
또는 $<-
제공 방법 environment
,하지만 "단일 브래킷"할당을 사용하여 클래스 ( [<-
) :
H <- new.env()
H[["key"]] <- rnorm(1)
key2 <- "xyz"
H[[key2]] <- data.frame(x = 1:3, y = letters[1:3])
H$another_key <- matrix(rbinom(9, 1, 0.5) > 0, nrow = 3)
H["error"] <- 42
#Error in H["error"] <- 42 :
# object of type 'environment' is not subsettable
R의 다른 패싯과 마찬가지로, 첫 번째 방법 ( object[[key]] <- value
)은 일반적으로 두 번째 ( object$key <- value
)보다 선호되기 때문에 전자의 경우 리터럴 값 대신 변수를 사용할 수 있습니다 (예 : 위의 예에서 key2
).
일반적으로 해시 맵 구현의 경우와 같이, environment
객체는 중복 키를 저장 하지 않습니다 . 기존 키에 대한 키 - 값 쌍을 삽입하려고하면 이전에 저장된 값이 바뀝니다.
H[["key3"]] <- "original value"
H[["key3"]] <- "new value"
H[["key3"]]
#[1] "new value"
주요 조회
마찬가지로 요소는 [[
또는 $
,하지만 [
:
H[["key"]]
#[1] 1.630631
H[[key2]] ## assuming key2 <- "xyz"
# x y
# 1 1 a
# 2 2 b
# 3 3 c
H$another_key
# [,1] [,2] [,3]
# [1,] TRUE TRUE TRUE
# [2,] FALSE FALSE FALSE
# [3,] TRUE TRUE TRUE
H[1]
#Error in H[1] : object of type 'environment' is not subsettable
해시지도 검사
일반 environment
이므로 해시 맵은 일반적인 방법으로 검사 할 수 있습니다.
names(H)
#[1] "another_key" "xyz" "key" "key3"
ls(H)
#[1] "another_key" "key" "key3" "xyz"
str(H)
#<environment: 0x7828228>
ls.str(H)
# another_key : logi [1:3, 1:3] TRUE FALSE TRUE TRUE FALSE TRUE ...
# key : num 1.63
# key3 : chr "new value"
# xyz : 'data.frame': 3 obs. of 2 variables:
# $ x: int 1 2 3
# $ y: chr "a" "b" "c"
rm
사용하여 요소를 제거 할 수 있습니다.
rm(list = c("key", "key3"), envir = H)
ls.str(H)
# another_key : logi [1:3, 1:3] TRUE FALSE TRUE TRUE FALSE TRUE ...
# xyz : 'data.frame': 3 obs. of 2 variables:
# $ x: int 1 2 3
# $ y: chr "a" "b" "c"
적응성
environment
객체를 해시 테이블로 사용하면 얻을 수있는 주요 이점 중 하나는 사실상 모든 유형의 객체를 값, 심지어 다른 environment
에도 저장할 수 있다는 것입니다.
H2 <- new.env()
H2[["a"]] <- LETTERS
H2[["b"]] <- as.list(x = 1:5, y = matrix(rnorm(10), 2))
H2[["c"]] <- head(mtcars, 3)
H2[["d"]] <- Sys.Date()
H2[["e"]] <- Sys.time()
H2[["f"]] <- (function() {
H3 <- new.env()
for (i in seq_along(names(H2))) {
H3[[names(H2)[i]]] <- H2[[names(H2)[i]]]
}
H3
})()
ls.str(H2)
# a : chr [1:26] "A" "B" "C" "D" "E" "F" "G" "H" "I" "J" "K" ...
# b : List of 5
# $ : int 1
# $ : int 2
# $ : int 3
# $ : int 4
# $ : int 5
# c : 'data.frame': 3 obs. of 11 variables:
# $ mpg : num 21 21 22.8
# $ cyl : num 6 6 4
# $ disp: num 160 160 108
# $ hp : num 110 110 93
# $ drat: num 3.9 3.9 3.85
# $ wt : num 2.62 2.88 2.32
# $ qsec: num 16.5 17 18.6
# $ vs : num 0 0 1
# $ am : num 1 1 1
# $ gear: num 4 4 4
# $ carb: num 4 4 1
# d : Date[1:1], format: "2016-08-03"
# e : POSIXct[1:1], format: "2016-08-03 19:25:14"
# f : <environment: 0x91a7cb8>
ls.str(H2$f)
# a : chr [1:26] "A" "B" "C" "D" "E" "F" "G" "H" "I" "J" "K" ...
# b : List of 5
# $ : int 1
# $ : int 2
# $ : int 3
# $ : int 4
# $ : int 5
# c : 'data.frame': 3 obs. of 11 variables:
# $ mpg : num 21 21 22.8
# $ cyl : num 6 6 4
# $ disp: num 160 160 108
# $ hp : num 110 110 93
# $ drat: num 3.9 3.9 3.85
# $ wt : num 2.62 2.88 2.32
# $ qsec: num 16.5 17 18.6
# $ vs : num 0 0 1
# $ am : num 1 1 1
# $ gear: num 4 4 4
# $ carb: num 4 4 1
# d : Date[1:1], format: "2016-08-03"
# e : POSIXct[1:1], format: "2016-08-03 19:25:14"
제한 사항
environment
객체를 해시 맵으로 사용하는 주요 제한 사항 중 하나는 R의 여러 측면과 달리 요소 조회 / 삽입에 벡터화가 지원되지 않는다는 것입니다.
names(H2)
#[1] "a" "b" "c" "d" "e" "f"
H2[[c("a", "b")]]
#Error in H2[[c("a", "b")]] :
# wrong arguments for subsetting an environment
Keys <- c("a", "b")
H2[[Keys]]
#Error in H2[[Keys]] : wrong arguments for subsetting an environment
객체에 저장되는 데이터의 특성에 따라 vapply
또는 list2env
를 사용하여 여러 요소를 한꺼번에 할당 할 수 있습니다.
E1 <- new.env()
invisible({
vapply(letters, function(x) {
E1[[x]] <- rnorm(1)
logical(0)
}, FUN.VALUE = logical(0))
})
all.equal(sort(names(E1)), letters)
#[1] TRUE
Keys <- letters
E2 <- list2env(
setNames(
as.list(rnorm(26)),
nm = Keys),
envir = NULL,
hash = TRUE
)
all.equal(sort(names(E2)), letters)
#[1] TRUE
위의 어느 것도 특히 간결하지만 키 - 값 쌍의 수가 큰 경우 for
루프 등을 사용하는 것이 더 좋을 수 있습니다.
패키지 : 해시
해시 패키지 는 R에서 해시 구조를 제공합니다. 그러나 삽입 및 읽기 모두에 대한 타이밍 용어는 환경을 해시로 사용하는 것과 비교할 만합니다. 이 문서는 단순히 그 존재를 인정하고 위의 이유로 아래의 샘플 타이밍 코드를 제공합니다. 해시가 오늘날 R 코드의 적절한 솔루션 인 경우는 확인되지 않았습니다.
중히 여기다:
# Generic unique string generator
unique_strings <- function(n){
string_i <- 1
string_len <- 1
ans <- character(n)
chars <- c(letters,LETTERS)
new_strings <- function(len,pfx){
for(i in 1:length(chars)){
if (len == 1){
ans[string_i] <<- paste(pfx,chars[i],sep='')
string_i <<- string_i + 1
} else {
new_strings(len-1,pfx=paste(pfx,chars[i],sep=''))
}
if (string_i > n) return ()
}
}
while(string_i <= n){
new_strings(string_len,'')
string_len <- string_len + 1
}
sample(ans)
}
# Generate timings using an enviornment
timingsEnv <- plyr::adply(2^(10:15),.mar=1,.fun=function(i){
strings <- unique_strings(i)
ht1 <- new.env(hash=TRUE)
lapply(strings, function(s){ ht1[[s]] <<- 0L})
data.frame(
size=c(i,i),
seconds=c(
system.time(for (j in 1:i) ht1[[strings[j]]]==0L)[3]),
type = c('1_hashedEnv')
)
})
timingsHash <- plyr::adply(2^(10:15),.mar=1,.fun=function(i){
strings <- unique_strings(i)
ht <- hash::hash()
lapply(strings, function(s) ht[[s]] <<- 0L)
data.frame(
size=c(i,i),
seconds=c(
system.time(for (j in 1:i) ht[[strings[j]]]==0L)[3]),
type = c('3_stringHash')
)
})
패키지 : listenv
package:listenv
는 환경에 대해리스트와 같은 인터페이스를 구현하지만, 해시와 같은 목적을위한 환경에 비례 한 성능은 해시 검색에서 좋지 않습니다. 그러나 인덱스가 숫자 인 경우 검색시 매우 빠를 수 있습니다. 그러나 그들은 package:future
와의 호환성 package:future
와 같은 다른 장점을 가지고 package:future
. 이 패키지를 그 목적으로 사용하는 것은 현재 주제의 범위를 넘어갑니다. 그러나 여기에 제공된 타이밍 코드는 쓰기 타이밍을위한 package : hash 예제와 함께 사용할 수 있습니다.
timingsListEnv <- plyr::adply(2^(10:15),.mar=1,.fun=function(i){
strings <- unique_strings(i)
le <- listenv::listenv()
lapply(strings, function(s) le[[s]] <<- 0L)
data.frame(
size=c(i,i),
seconds=c(
system.time(for (k in 1:i) le[[k]]==0L)[3]),
type = c('2_numericListEnv')
)
})