Как вывернуть список наизнанку? - PullRequest
0 голосов
/ 13 января 2019

У меня есть следующий список:

> list(c(3, 4, 5, 8), c(2, 6, 9, 10), c(1, 7))
[[1]]
[1] 3 4 5 8

[[2]]
[1]  2  6  9 10

[[3]]
[1] 1 7

Таким образом, мы можем сказать, что 3 принадлежит группе 1, 6 принадлежит группе 2, 7 принадлежит группе 3 и так далее. Мне нужно обратное отображение, т. Е. Для каждого номера, к которому я хочу иметь идентификатор группы, к которой он принадлежит (см. Ожидаемый результат):

> list(3, 2, 1, 1, 1, 2, 3, 1, 2, 2)
[[1]]
[1] 3

[[2]]
[1] 2

[[3]]
[1] 1

[[4]]
[1] 1

[[5]]
[1] 1

[[6]]
[1] 2

[[7]]
[1] 3

[[8]]
[1] 1

[[9]]
[1] 2

[[10]]
[1] 2

Я думал, что purrr::transpose должен делать эту работу, но она точно не выполняет то, что я намереваюсь, не так ли? Как это можно сделать?

PS. В конечном счете, мне нужен просто вектор формы: 3 2 1 1 1 2 3 1 2 2, но с учетом вышесказанного я думаю, что unlist() достаточно для преобразования.

Ответы [ 7 ]

0 голосов
/ 14 января 2019

Решение с использованием purrr. dat2 - конечный результат, целочисленный вектор.

dat <- list(c(3, 4, 5, 8), c(2, 6, 9, 10), c(1, 7))

library(purrr)

dat2 <- dat %>%
  imap(~set_names(.x, rep(.y, length(.x)))) %>%
  unlist() %>%
  sort() %>%
  names() %>%
  as.integer()
dat2
# [1] 3 2 1 1 1 2 3 1 2 2
0 голосов
/ 14 января 2019

Используя tidyverse и purr::imap_dfr, мы можем создать tibble со значениями и индексами рядом, arrange по значению и pull индексы:

list_ <- list(c(3, 4, 5, 8), c(2, 6, 9, 10), c(1, 7))
library(tidyverse)
imap_dfr(list_,~tibble(.x,.y)) %>% arrange(.x) %>% pull(.y) %>% as.list

# [[1]]
# [1] 3
# 
# [[2]]
# [1] 2
# 
# [[3]]
# [1] 1
# 
# [[4]]
# [1] 1
# 
# [[5]]
# [1] 1
# 
# [[6]]
# [1] 2
# 
# [[7]]
# [1] 3
# 
# [[8]]
# [1] 1
# 
# [[9]]
# [1] 2
# 
# [[10]]
# [1] 2

Менее красиво переведено в базу R (тот же вывод):

with(
  as.data.frame(do.call(rbind,Map(cbind,a = list_, b =seq_along(list_)))),
  as.list(b[order(a)]))
0 голосов
/ 13 января 2019

Также в base, как-то так

L <- as.list(setNames( rep(1:length(lengths(l)), lengths(l)), unlist(l)))
# if wanted, sort it with
L[as.character(sort(as.integer(names(L))))]
# if wanted, unname with
unname(L)

с l <- list(c(3, 4, 5, 8), c(2, 6, 9, 10), c(1, 7)).

Или в функции

list_inside_out <- function (l, unName = TRUE) { 
  l2 <- lengths(l)
  out <- as.list(setNames(rep(1:length(l2), l2), unlist(l)))
  out <- out[as.character(sort(as.integer(names(out))))] 
  if (unName) return(unname(out))
  out
}
list_inside_out(l)
# [[1]]
# [1] 3
# 
# [[2]]
# [1] 2
# 
# [[3]]
# [1] 1
# ...
0 голосов
/ 13 января 2019

Могу ли я предложить старомодный цикл:

# your list
x <- list(c(3, 4, 5, 8), c(2, 6, 9, 10), c(1, 7))
# the data in the list as vector
num <- unlist( x )
# the variable that will be the position vector
pos <- NULL

# loop through the possible position, see which number it contains
# find which "group it belongs to, and add that finding to the position vector
for( i in 1:length( num ) )
    for( j in  1:length( x ) )
        if( i %in% x[[j]] ) pos <- c( pos, j )

pos
[1] 3 2 1 1 1 2 3 1 2 2
0 голосов
/ 13 января 2019
x <- list(c(3, 4, 5, 8), c(2, 6, 9, 10), c(1, 7))

Следующие 3 формы получат одинаковые выходные данные:

library(tidyverse)

# (1)
x %>% set_names(1:3) %>% stack %>% arrange(values) %>% select(ind)

# (2)
x %>% enframe %>% unnest %>% arrange(value) %>% select(name)

# (3)
x %>% (reshape2::melt) %>% arrange(value) %>% select(L1)
0 голосов
/ 13 января 2019

Проверьте это решение:

library(tidyverse)
library(magrittr)
library(wrapr)

list(c(3, 4, 5, 8), c(2, 6, 9, 10), c(1, 7)) %.>%
  tibble(x = .) %>%
  mutate(rn = row_number()) %>%
  unnest() %>%
  arrange(x) %$%
  set_names(rn, x) %>%
  as.list()
0 голосов
/ 13 января 2019

Вот базовое решение ...

list <- list(c(3, 4, 5, 8), c(2, 6, 9, 10), c(1, 7))

rep(1:length(list), sapply(list, length))[order(unlist(list))]
...