0

I have a list:

myList
$`0`
$`0`$item1
numeric(0)

$`0`$item2
[1] 350

$`0`$item3
numeric(0)


$`1`
$`1`$item1
numeric(0)

$`1`$item2
[1] 56

$`1`$item3
numeric(0)

I am using an sapply function on this list, but get an error:

invalid 'type' (list) of argument

how can i convert all numeric(0) to 0, like the other items?

Nneka
  • 1,764
  • 2
  • 15
  • 39
  • Please show the code that you’re using to `sapply` over the list. The error message makes it sound like the error is elsewhere. – Konrad Rudolph Apr 13 '21 at 11:07
  • 1
    FYI `sapply` is an unpredictable function. If you know you've got a list going in and a list coming out, use `lapply`. For other outputs, try the `map` function family in `purrr` – Captain Hat Apr 13 '21 at 11:15

4 Answers4

2

Assuming you only have a 1 depth-list this is the shortest solution

my_list[lengths(my_list) == 0] <- 0

for 2 depth list

my_list <- lapply(my_list, function(x)x[lengths(x) == 0] <- 0)
Oliver
  • 8,169
  • 3
  • 15
  • 37
  • Good point @KonradRudolph. Forgot to consider the recommended method for multi-assignment `.. <- .. <- ..`. – Oliver Apr 13 '21 at 12:14
2

In case the depth is not known or not equal you can use a recursive function:

f <- function(x) {
  if(is.list(x)) lapply(x, f)
  else ifelse(length(x) == 0, 0, x)
}

f(myList)
#$`0`
#$`0`$item1
#[1] 0
#
#$`0`$item2
#[1] 350
#
#$`0`$item3
#[1] 0
#
#
#$`1`
#$`1`$item1
#[1] 0
#
#$`1`$item2
#[1] 56
#
#$`1`$item3
#[1] 0
#
#
#$`2`
#[1] 4
#
#$`3`
#[1] 0

Data:

myList <- list(`0` = list(item1 = numeric(0), item2 = 350, item3 = numeric(0)),
               `1` = list(item1 = numeric(0), item2 = 56, item3 = numeric(0)),
               `2` = 4, `3` = numeric(0))
GKi
  • 37,245
  • 2
  • 26
  • 48
0

Use purrr's modify()

newList <- purrr::modify(myList, ~ if(length(.) == 0){ 
                                   0 
                                   } else { . })

Or use base::lapply

newList <- lapply(myList, function(x){
if(length(x) == 0){
out <- 0
} else {
out <- x
}
return(out)
})
Captain Hat
  • 2,444
  • 1
  • 14
  • 31
  • 1
    Why the `out` variable in the `lapply` example? Just use the same code as for `modify`, it’s cleaner and more readable (you can also drop the redundant braces). – Konrad Rudolph Apr 13 '21 at 11:45
  • Just habit - I like functions to only have a single return statement. For some reason I think /code differently when using the `~ f(.)` notation. – Captain Hat Apr 13 '21 at 12:37
  • 1
    You probably misunderstood my comment, I don’t recommend having multiple `return` calls. In fact, I recommend not using `return` *at all!* — it’s redundant here (and not the good kind of redundant). [Omitting the `return` call makes the code shorter and more readable](https://stackoverflow.com/a/59090751/1968) and eliminates unnecessary control flow: `function (x) if (length(x) == 0L) 0 else x`. – Konrad Rudolph Apr 13 '21 at 13:18
0

using nested lapply

lapply(my_list, function(x) lapply(x, function(x) ifelse(length(x) == 0, 0, x)))
$`0`
$`0`$item1
[1] 0

$`0`$item2
[1] 350

$`0`$item3
[1] 0


$`1`
$`1`$item1
[1] 0

$`1`$item2
[1] 56

$`1`$item3
[1] 0

or sapply inside lapply

lapply(my_list, function(x) sapply(x, function(x) ifelse(length(x) == 0, 0, x)))

$`0`
item1 item2 item3 
    0   350     0 

$`1`
item1 item2 item3 
    0    56     0 

or using sapply both inside & outside

sapply(my_list, function(x) sapply(x, function(x) ifelse(length(x) == 0, 0, x)))

        0  1
item1   0  0
item2 350 56
item3   0  0

on the list

my_list <- list(`0` = list(item1 = numeric(0), item2 = 350, item3 = numeric(0)),
                `1` = list(item1 = numeric(0), item2 = 56, item3 = numeric(0)))
AnilGoyal
  • 25,297
  • 4
  • 27
  • 45