У меня есть список элементов с разным количеством элементов, многие из которых являются подмножествами друг друга. Я хотел бы удалить все элементы, полный набор элементов которых существует в других элементах.
Так, например, для:
listy<-list("item1"=c(10,210,300,400,500,600), "item2"=c(10,210,300), "item3"=c(500,600), "item4"=c(210, 300), "item5"=c(700,800,900))
Пункты 2,3 и 4 являются подмножествами пункта 1, поэтому мой желаемый результат:
listy2<-c("item1"=c(10,210,300,400,500,600), "item5"=c(700,800,900))
До сих пор я пытался преобразовать его в тиббл, сортировать по первому столбцу, а затем удалять дубликаты первого столбца. Но это очень неэффективно и удаляет только те, которым соответствует первый столбец, а не те, где совпадают последующие (например, item3 и item4 по сравнению с item1 здесь). Или я мог бы сделать цикл для всех против всех grepl, создавая строки поиска для каждого элемента в списке. Пример: что-то вроде этого, но на самом деле это не работает из-за строки поиска:
for(ity in 1:length(listy)){
if (grepl(paste(unlist(listy[[ity]]), sep = "|"), listy[[c(1:3)[-ity]]])){
print(ity)
}}
Но опять же, это было бы очень неэффективно (а мои фактические списки содержат 100 000 элементов или более, каждый из которых содержит до 20 000 элементов). Я уверен, что мне не хватает какой-то очень простой функции, и любая помощь будет принята с благодарностью.
idx <- sapply(seq_along(listy), \(i) any(sapply(listy[-i], \(j) all(listy[[i]] %in% j))))
listy[!idx]
# $item1
# [1] 10 210 300 400 500 600 500
#
# $item5
# [1] 700 800 900
Как это работает
По сути, это двойной цикл. Первый sapply
перебирает индекс (i
) всех элементов в вашем списке. Второй sapply
перебирает все элементы вашего списка, кроме i
, и сравнивает их. Вам необходимо удалить этот индекс, иначе совпадение всегда будет.
Вот версия происходящего, чтобы помочь вам визуализировать:
for (i in seq_along(listy)) {
for (j in listy[-i]) {
lgl <- all(list[[i]] %in% j)
cat("All c(", toString(listy[[i]]), ") in c(", toString(j), ")? --> ", lgl, "\n", sep = "")
}
}
@gpo Конечно! Я добавил раздел, чтобы помочь вам понять, надеюсь, это имеет смысл. Я не уверен, что вы имеете в виду под словами «Я никогда раньше не видел () в этом контексте». Вы имеете в виду \(i)
?
Вот igraph
вариант
library(igraph)
outer(listy, listy, Vectorize(\(x, y) all(y %in% x))) %>%
graph_from_adjacency_matrix(diag = FALSE) %>%
degree(mode = "in") %>%
subset(. == 0) %>%
names() %>%
`[`(listy, .)
который дает
$item1
[1] 10 210 300 400 500 600
$item5
[1] 700 800 900
Потрясающий! Спасибо! Можно ли объяснить, как это работает? Я никогда раньше не видел () в этом контексте.