jsonliteで要素ひとつだけのベクトルをうまくtoJSON()する
追記(2014/10/02):
toJSON()
にはauto_unbox
というオプションがあって、それをTRUEにしとけば自動でいい感じにしてくれると教えてもらいました。
jsonliteで要素ひとつだけのベクトルをうまくtoJSON()するにはauto_unboxを使えばいい - Technically, technophobic.
ということで、以下で書いている、手動でunbox
するのは無駄な努力でした。。
auto_unbox
使いましょう。
前回(jsonliteにもやっとした - Technically, technophobic.)書いたけど、
jsonlite
はすばらしいけど要素ひとつだけのベクトルをうまくtoJSON()
できない。
こんな感じ。
> library(jsolite) > json_str <- '{ "x" : 1 }' > json_obj <- fromJSON(json_str) > cat(toJSON(json_obj)) { "x" : [ 1 ] }
で、なんかやり方ないかなーと探してたら、unbox
という関数があるらしい。
OpenCPU - Release of jsonlite 0.9.4
The new
unbox
function was requested several users. It can be used to force atomic vectors of length 1 to be encoded as aJSON
scalar rather than an array.
こんな感じ。
# unboxを使わないと > cat(toJSON(list(x=1))) { "x" : [ 1 ] } # unboxを使うと… > cat(toJSON(list(x=unbox(1)))) { "x" : 1 }
おおー、これこれ。
ということで、まあできそうです。お騒がせしました。
ネストしまくったlistに再帰的に関数を適用するには、rapply
という関数があるらしいです。
(存在を忘れてた。。)
こんな感じ。
> a <- list(a=1, b=c(1,2,3), c=list(x=1, y=c(2,3))) > (a_unboxed <- rapply(a, function(x) if(length(x) == 1) unbox(x) else x, how="list")) $a [1] 1 attr(,"class") [1] "scalar" "numeric" $b [1] 1 2 3 $c $c$x [1] 1 attr(,"class") [1] "scalar" "numeric" $c$y [1] 2 3 > cat(toJSON(a_unboxed)) { "a" : 1, "b" : [ 1, 2, 3 ], "c" : { "x" : 1, "y" : [ 2, 3 ] } }
(ちなみにこれ、if...else...
構文でなくifelse()
関数でやろうとしたらうまくいきません。
なんででしょう。。)
> (a_unboxed <- rapply(a, function(x) ifelse(length(x) == 1, unbox(x), x), how="list")) $a [1] 1 $b [1] 1 $c $c$x [1] 1 $c$y [1] 2
(追記) 理由分かりました。ブログを書きました↓