UPDATE: 2022-12-15 20:21:56

はじめに

Rには非公開のクラスがいくつかある。例えば、Dlistなんかもそう。listではない、Dlistである。他にもあるようだけど、ここでは、Dlistについてまとめておく。

Dlist

Dlistはキャラクタータイプの一種で、Sys.getenv()などのシステム関係の返り値のクラスを調べると出てくる。

tmp <- Sys.getenv()
list(class(tmp), typeof(tmp))
## [[1]]
## [1] "Dlist"
## 
## [[2]]
## [1] "character"

調べると、RのBaseパッケージで定義されている非公式のクラスらしく、名前付き文字ベクトルを「きれい」にフォーマットして出力することを目的にしているとのこと。適当に名前付きのベクトルを作成して、クラスをDlistにしてからprint()してみると、フォーマットして出力される。

string <- c("A" = "a", "B" = "bbb", "C" = "ccccc"); 
string
##       A       B       C 
##     "a"   "bbb" "ccccc"
class(string) <- "Dlist"
print(string)
## A                       a
## B                       bbb
## C                       ccccc

Dlistクラスのprint()メソッド、print.Dlist実装をみると、formatDL()という関数に渡しているようで、formatDL()はフォーマットしてくれる関数らしいんだが、データフレームにはしてくれないよう。だけどデータフレームとし扱いたい理由があったので、無理くり変換する。クラスをNULLにしてas_tibble()すると、行名にキーが入って、列名に値がはいる。

Sys.getenv2 <- function() {
  value <- Sys.getenv()
  class(value) <- NULL
  df <- tibble::as_tibble(value, rownames = "key")
  return(df)
}

x <- Sys.getenv2()
head(x)
## # A tibble: 6 × 2
##   key                        value                                              
##   <chr>                      <chr>                                              
## 1 __CF_USER_TEXT_ENCODING    0x1F5:0x1:0xE                                      
## 2 __CFBundleIdentifier       org.rstudio.RStudio                                
## 3 CLICOLOR_FORCE             1                                                  
## 4 COMMAND_MODE               unix2003                                           
## 5 DISPLAY                    /private/tmp/com.apple.launchd.brxZuJZ1Tn/org.xqua…
## 6 DYLD_FALLBACK_LIBRARY_PATH /Library/Frameworks/R.framework/Resources/lib:/Lib…

クラスを持ってないオブジェクトに対して、as_tibble()がうまく作用する理屈は・・・。こんな名前付きの文字型ベクトルがあったとして、これを無理やりクラスをDlistにしてみると、こうなる。

val <- c("A" = "a", "B" = "b", "C" = "c")
class(val) <- "Dlist"
list(val,class(val))
## [[1]]
## A                       a
## B                       b
## C                       c
## 
## [[2]]
## [1] "Dlist"

これのクラスをNULLにしよう。そうするとDlistからcharacterに変換される。この状態では、名前付きの文字型ベクトルなので、

class(val) <- NULL
list(class(val), val)
## [[1]]
## [1] "character"
## 
## [[2]]
##   A   B   C 
## "a" "b" "c"

データフレームに変換すれば、行名付きのデータフレームになるので、そこからは行名を列に取り出せばデータフレームの完成。

tibble::as_tibble(val, rownames = "key")
## # A tibble: 3 × 2
##   key   value
##   <chr> <chr>
## 1 A     a    
## 2 B     b    
## 3 C     c

ちなみにformatDL()は下記のようにしてフォーマットを整えることができる。

# class(string) <- "Dlist"
cat(formatDL(string, style = "list", width = 20), sep = "\n")
## A: a
## B: bbb
## C: ccccc

そしてちなみに、下記のdf2*の意味を今更知った・・・行名があるかないかなのね。

val <- c("A" = "a", "B" = "b", "C" = "c")
df1 <- tibble::as_tibble(val, rownames = NULL)
list(df1, row.names(df1))
## [[1]]
## # A tibble: 3 × 1
##   value
##   <chr>
## 1 a    
## 2 b    
## 3 c    
## 
## [[2]]
## [1] "1" "2" "3"
df2 <- tibble::as_tibble(val, rownames = NA)
list(df2, row.names(df2))
## [[1]]
## # A tibble: 3 × 1
##   value
## * <chr>
## 1 a    
## 2 b    
## 3 c    
## 
## [[2]]
## [1] "A" "B" "C"

誰得な内容になってしまったが、Dlistといものがあるみたい。