Reputation: 13100
Is there a "built-in"/efficient and robust way to check if list objects are nested or not?
To clarify my understanding of the term nested:
Flat or not-nested list
x.1 <- list(
a=TRUE,
b=1:5
)
Nested list
x.2 <- list(
a=list(a.1=list(a.1.1=TRUE)),
b=list(b.1=1:5)
)
My first idea was to use a combination of str
, capture.output
and regular expressions. But as everything related to regular expression: pretty powerful, pretty risky on the robustness side ;-) So I wondered if there's something better out there:
isNested <- function(x) {
if (class(x) != "list") {
stop("Expecting 'x' to be a list")
}
out <- FALSE
strout <- capture.output(str(x))
idx <- grep("\\$.*List", strout)
if (length(idx)) {
out <- TRUE
}
return(out)
}
> isNested(x=x.1)
[1] FALSE
> isNested(x=x.2)
[1] TRUE
Second approach courtesy of Roman and Arun:
isNested2 <- function(x) {
if (class(x) != "list") {
stop("Expecting 'x' to be a list")
}
out <- any(sapply(x, is.list))
return(out)
}
> isNested2(x=x.1)
[1] FALSE
> isNested2(x=x.2)
[1] TRUE
Upvotes: 6
Views: 1862
Reputation: 6584
What if the contents of the list are S3 objects which in turn have a nested list? I'd want these not to be treated as lists, so that a list of these objects is "not nested" (it's just a list of objects rather than a list of lists). Using class()
rather than is.list()
so that check if literally list rather than something else with an embedded list.
is.nested <- function(x) {
stopifnot(is.list(x))
any(sapply(x, function(x) any(class(x) == "list")))
}
Upvotes: 0
Reputation: 81743
You can use the is.list
function:
any(sapply(x.1, is.list))
[1] FALSE
any(sapply(x.2, is.list))
[1] TRUE
As a function isNested
:
isNested <- function(l) {
stopifnot(is.list(l))
for (i in l) {
if (is.list(i)) return(TRUE)
}
return(FALSE)
}
Instead of testing all list elements, the function stops as soon as it detects a nested list.
Upvotes: 12
Reputation: 7536
Here's another way for the fun of it:
length(unlist(l, FALSE)) != length(unlist(l))
Or a variation on that:
!identical(unlist(l, FALSE), unlist(l))
Makes use of the recursive
parameter of unlist()
. With the error checking as well if you want:
isNested <- function(l) {
if (!is.list(l)) stop("Not a list.")
!identical(unlist(l, FALSE), unlist(l))
}
Upvotes: 3
Reputation: 12411
Try this :
isNested <- function(x) {
if (is.list(x))
stop("Expecting 'x' to be a list")
any(unlist( lapply(x,is.list) ))
}
Upvotes: 4