Найти позицию индекса во вложенных списках для совпадения

Я хочу найти индексы соответствия вложенного списка и целевого значения (11).

Данные:

f <- list(
  list(1, 2, 3),
  list(4, 5, list(8, list(11, 12)))
)

Желаемый результат для целевого значения = 11.:

c(2, 3, 2, 1)

Отпечатано:

 f
[[1]]
[[1]][[1]]
[1] 1

[[1]][[2]]
[1] 2

[[1]][[3]]
[1] 3


[[2]]
[[2]][[1]]
[1] 4

[[2]][[2]]
[1] 5

[[2]][[3]]
[[2]][[3]][[1]]
[1] 8

[[2]][[3]][[2]]
--->>>  [[2]][[3]][[2]][[1]]  <<<----
-->>>> [1] 11 <<<----

[[2]][[3]][[2]][[2]]
[1] 12

Что я пробовал:

сопоставьте с unlist(data), ищите параметр в which() и ищите arrInd().

Я бы не использовал многократные циклы for в R. Лучше было бы делать все циклы в C, C++,... Перед тем, как реализовывать это самостоятельно, я хотел проверить, не пропускаю ли функцию.

Ответы

Ответ 1

Вы можете попробовать melt() из reshape2:

melted_lst <- reshape2::melt(f) 
melted_lst[sort(colnames(melted_lst))][melted_lst$value == 11, ]

  L1 L2 L3 L4 value
7  2  3  2  1    11

Или с melt() из data.table (как упомянуто @IceCreamToucan):

melted_lst <- data.table::melt(f)
melted_lst[sort(colnames(melted_lst))][melted_lst$value == 11, ]

Ответ 2

foo = function(x, sep = ".") {
    names(x) = paste0(seq_along(x))
    while(any(sapply(x, class) == "list")) {
        ind = sapply(x, class) == "list"
        temp = unlist(x[ind], recursive = FALSE)
        names(temp) = paste0(rep(names(x)[ind], lengths(x[ind])),
                             sep,
                             sequence(lengths(x[ind])))
        x = c(x[!ind], temp)
    }
    return(x)
}
f2 = foo(f)
names(which(unlist(f2) == 11))
#[1] "2.3.2.1"

Ответ 3

Еще один дубль с использованием tibble::enframe():

library(tidyverse)
f <- list(
  list(1, 2, 3),
  list(4, 5, list(8, list(11, 12)))
)

df <- enframe(f)
while(!all(lengths(df$value)==1)) df <- df %>% 
  mutate(value = map(value,~enframe(.) %>% mutate_at("value", as.list))) %>%
  unnest(value)
df <- df %>% unnest(value)
df
#> # A tibble: 8 x 5
#>    name name1 name2 name3 value
#>   <int> <int> <int> <int> <dbl>
#> 1     1     1     1     1     1
#> 2     1     2     1     1     2
#> 3     1     3     1     1     3
#> 4     2     1     1     1     4
#> 5     2     2     1     1     5
#> 6     2     3     1     1     8
#> 7     2     3     2     1    11
#> 8     2     3     2     2    12

filter(df, value == 11) %>%
  select(-value) %>%
  unlist(use.names = F)
#> [1] 2 3 2 1