有人刚刚发布了一些控制台输出作为示例。 (这种情况发生了很多,我有转换矢量和数据帧的打印输出的策略。)我想知道是否有人有一个优雅的方法将其解析为真正的R列表?
test <- "[[1]]
[1] 1.0000 1.9643 4.5957
[[2]]
[1] 1.0000 2.2753 3.8589
[[3]]
[1] 1.0000 2.9781 4.5651
[[4]]
[1] 1.0000 2.9320 3.5519
[[5]]
[1] 1.0000 3.5772 2.8560
[[6]]
[1] 1.0000 4.0150 3.1937
[[7]]
[1] 1.0000 3.3814 3.4291"
这是命名和未命名节点的示例:
L <-
structure(list(a = structure(list(d = 1:2, j = 5:6, o = structure(list(
w = 2, 4), .Names = c("w", ""))), .Names = c("d", "j", "o"
)), b = "c", c = 3:4), .Names = c("a", "b", "c"))
> L
$a
$a$d
[1] 1 2
$a$j
[1] 5 6
$a$o
$a$o$w
[1] 2
$a$o[[2]]
[1] 4
$b
[1] "c"
$c
[1] 3 4
我已经完成了str
如何处理列表的代码,但它本质上是在进行逆转换。我认为这需要在这些方面进行一些结构化,其中将会对这种逻辑进行递归调用,因为可以命名列表(在最后一个索引之前会有&#34; $&#34;)或未命名(在这种情况下,将有一个数字括在&#34; [[。]]&#34;。
parseTxt <- function(Lobj) {
#setup logic
# Untested code... basically a structure to be filled in
rdLn <- function(Ln) {
for( ln in length(inp) ) {
m <- gregexpr("\\[\\[|\\$", "$a$o[[2]]")
separators <- regmatches("$a$o[[2]]", m)
curr.nm=NA
if ( tail( separators, 1 ) == "$" ){
nm <- sub("^.+\\$","",ln)
if( !nm %in% curr.nm){ curr.nm <-c(nm, curr.nm) }
} else { if (tail( separators, 1 ) == '[[' ){
# here need to handle "[[n]]" case
} else { and here handle the "[n]" case
}
}
}
答案 0 :(得分:8)
这是我的解决方案。它适用于您的测试用例以及我测试过的其他几个测试用例。
deprint <- function(ll) {
## Pattern to match strings beginning with _at least_ one $x or [[x]]
branchPat <- "^(\\$[^$[]*|\\[\\[[[:digit:]]*\\]\\])"
## Pattern to match strings with _just_ one $x or one [[x]]
trunkPat <- "^(\\$[^$[]*|\\[\\[[[:digit:]]*\\]\\])\\s*$"
##
isBranch <- function(X) {
grepl(branchPat, X[1])
}
## Parse character vectors of lines like "[1] 1 3 4" or
## "[1] TRUE FALSE" or c("[1] a b c d", "[5] e f")
readTip <- function(X) {
X <- paste(sub("^\\s*\\[.*\\]", "", X), collapse=" ")
tokens <- scan(textConnection(X), what=character(), quiet=TRUE)
read.table(text = tokens, stringsAsFactors=FALSE)[[1]]
}
## (0) Split into vector of lines (if needed) and
## strip out empty lines
ll <- readLines(textConnection(ll))
ll <- ll[ll!=""]
## (1) Split into branches ...
trunks <- grep(trunkPat, ll)
grp <- cumsum(seq_along(ll) %in% trunks)
XX <- split(ll, grp)
## ... preserving element names, where present
nms <- sapply(XX, function(X) gsub("\\[.*|\\$", "", X[[1]]))
XX <- lapply(XX, function(X) X[-1])
names(XX) <- nms
## (2) Strip away top-level list identifiers.
## pat2 <- "^\\$[^$\\[]*"
XX <- lapply(XX, function(X) sub(branchPat, "", X))
## (3) Step through list elements:
## - Branches will need further recursive processing.
## - Tips are ready to parse into base type vectors.
lapply(XX, function(X) {
if(isBranch(X)) deprint(X) else readTip(X)
})
}
使用L
,您的更复杂的示例列表,这是它给出的内容:
## Because deprint() interprets numbers without a decimal part as integers,
## I've modified L slightly, changing "list(w=2,4)" to "list(w=2L,4L)"
## to allow a meaningful test using identical().
L <-
structure(list(a = structure(list(d = 1:2, j = 5:6, o = structure(list(
w = 2L, 4L), .Names = c("w", ""))), .Names = c("d", "j", "o"
)), b = "c", c = 3:4), .Names = c("a", "b", "c"))
## Capture the print representation of L, and then feed it to deprint()
test2 <- capture.output(L)
LL <- deprint(test2)
identical(L, LL)
## [1] TRUE
LL
## $a
## $a$d
## [1] 1 2
##
## $a$j
## [1] 5 6
##
## $a$o
## $a$o$w
## [1] 2
##
## $a$o[[2]]
## [1] 4
##
## $b
## [1] "c"
##
## $c
## [1] 3 4
以下是它如何处理test
的打印表示,这是您更常规的列表:
deprint(test)
## [[1]]
## [1] 1.0000 1.9643 4.5957
##
## [[2]]
## [1] 1.0000 2.2753 3.8589
##
## [[3]]
## [1] 1.0000 2.9781 4.5651
##
## [[4]]
## [1] 1.0000 2.9320 3.5519
##
## [[5]]
## [1] 1.0000 3.5772 2.8560
##
## [[6]]
## [1] 1.0000 4.0150 3.1937
##
## [[7]]
## [1] 1.0000 3.3814 3.4291
又一个例子:
head(as.data.frame(deprint(capture.output(as.list(mtcars)))))
# mpg cyl disp hp drat wt qsec vs am gear carb
# 1 21.0 6 160 110 3.90 2.620 16.46 0 1 4 4
# 2 21.0 6 160 110 3.90 2.875 17.02 0 1 4 4
# 3 22.8 4 108 93 3.85 2.320 18.61 1 1 4 1
# 4 21.4 6 258 110 3.08 3.215 19.44 1 0 3 1
# 5 18.7 8 360 175 3.15 3.440 17.02 0 0 3 2
# 6 18.1 6 225 105 2.76 3.460 20.22 1 0 3 1
答案 1 :(得分:4)
我不会称之为#34;优雅&#34;,但是对于未命名的列表,您可以对这些内容进行一些检查/修改:
s <- strsplit(gsub("\\[+\\d+\\]+", "", test), "\n+")[[1]][-1]
lapply(s, function(x) scan(text = x, what = double(), quiet = TRUE))
[[1]]
[1] 1.0000 1.9643 4.5957
[[2]]
[1] 1.0000 2.2753 3.8589
[[3]]
[1] 1.0000 2.9781 4.5651
[[4]]
[1] 1.0000 2.9320 3.5519
[[5]]
[1] 1.0000 3.5772 2.8560
[[6]]
[1] 1.0000 4.0150 3.1937
[[7]]
[1] 1.0000 3.3814 3.4291
当然,这仅适用于列表,此特定示例具体为what = double()
,因此需要进行额外检查。弹出我的脑袋以检测列表中的字符元素的想法是制作what
参数
what = if(length(grep("\"", x))) character() else double()