Как вывернуть список наизнанку?

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

> 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() достаточно для преобразования.

Приношу свои извинения, но я не могу понять, как получить 3 2 1 1 1 2 3 1 2 2 из заданного ввода, по крайней мере, мне это не ясно. Спасибо

PKumar 13.01.2019 08:03

@PKumar: 1 в группе 3, 2 в группе 2, 3 в группе 1, 4 в группе 1, 5 в группе 1 ...

Khaynes 13.01.2019 08:08

Мы начинаем с 1 и смотрим, к какой группе 1 принадлежит - мы видим, что это в 3-й группе, а именно в 3-м элементе списка. Затем мы идем с 2:10 и проверяем то же самое.

jakes 13.01.2019 08:08
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
8
3
465
7

Ответы 7

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

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))]

Хорошее решение, вы можете полностью векторизовать это с помощью rep(seq_along(l), lengths(l))[order(unlist(l))] (не уверен, для чего вы используете as.numeric).

David Arenburg 13.01.2019 09:25

По поводу «не совсем отвечает на мой главный вопрос с преобразованием списка наизнанку», думаю, вам нужно уточнить свой вопрос. То, как вы описываете и представляете желаемый результат, кажется, что вы просто хотите получить индекс списка для каждого значения (чего достигают этот и другие ответы). Я не вижу «вывернутой наизнанку» части;)

Henrik 13.01.2019 11:11

@DavidArenburg Хороший замечание (исходное решение было немного длиннее, так что это был всего лишь шум ;-))

Khaynes 13.01.2019 23:03

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

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()

5-я строчка это ошибка %.>%?

Khaynes 13.01.2019 09:00

Нет. Это труба из упаковки wrapr.

Paweł Chabros 13.01.2019 09:11

Почему вы дополнительно используете %.>% в оболочке вместо использования %>% в tidyverse? В этом случае они получат такой же результат.

Darren Tsai 13.01.2019 09:19
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)

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

# 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

Также в 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
# ...

Решение с использованием 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

Используя 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)]))

Другие вопросы по теме