У меня есть два длинных списка A и B, которые имеют одинаковую длину, но содержат разное количество эквивалентных элементов:
Список A может содержать множество элементов, которые также могут повторяться в одном и том же поле.
Список B содержит либо только один элемент, либо пустое поле, то есть «символ (0)».
A также содержит несколько пустых полей, но для этих записей всегда присутствует элемент в B, поэтому нет записей с пустыми полями в A и B.
Я хочу объединить элементы A и B в новый список той же длины, C, в соответствии со следующими правилами:
- Все элементы из A должны присутствовать в C, включая их потенциальные повторения в том же поле.
- Если B содержит элемент, которого еще нет в A той же записи, он также будет добавлен в C.
- Но если B содержит элемент, который уже присутствует в A той же записи, он будет проигнорирован.
- Если у A есть пустое поле, элемент из B для этой записи будет добавлен в C.
- Если B имеет пустое поле, элементы из A для этой записи будут добавлены в C.
Это пример того, как начинаются эти списки:
> A
[1] "JAMES" "JAMES"
[2] "JOHN" "ROBERT"
[3] "WILLIAM" "MICHAEL" "WILLIAM" "DAVID" "WILLIAM"
[4] character(0)
...
> B
[1] "RICHARD"
[2] "JOHN"
[3] character(0)
[4] "CHARLES"
...
Это правильный результат, который я ищу:
> C
[1] "JAMES" "JAMES" "RICHARD"
[2] "JOHN" "ROBERT"
[3] "WILLIAM" "MICHAEL" "WILLIAM" "DAVID" "WILLIAM"
[4] "CHARLES"
...
Я пробовал, например:
C <- sapply(mapply(union, A,B), setdiff, character(0))
Но, к сожалению, это удалило повторения из A:
> C
[1] "JAMES" "RICHARD"
[2] "JOHN" "ROBERT"
[3] "WILLIAM" "MICHAEL" "DAVID"
[4] "CHARLES"
...
Кто-нибудь может сказать мне, пожалуйста, как объединить эти два списка, сохранить повторения из A и добиться желаемого результата?
Заранее большое спасибо!
Обновление. Машиночитаемые данные:
A <- list(c("JAMES","JAMES"),
c("JOHN","ROBERT"),
c("WILLIAM","MICHAEL","WILLIAM","DAVID","WILLIAM"),
character(0))
B <- list("RICHARD","JOHN",character(0),"CHARLES")
1 ответ
Вот ваш фрагмент данных в воспроизводимой форме:
A <- list(c("JAMES","JAMES"),
c("JOHN","ROBERT"),
c("WILLIAM","MICHAEL","WILLIAM","DAVID","WILLIAM"),
character(0))
B <- list("RICHARD","JOHN",character(0),"CHARLES")
Вы были близки с mapply()
. Я получил желаемый результат, используя c()
для объединения элементов списка в A
и B
, но мне пришлось манипулировать элементами предоставленных векторов, поэтому я придумал следующее:
foo <- function(...) {
l1 <- length(..1)
l2 <- length(..2)
out <- character(0)
if(l1 > 0) {
if(l2 > 0) {
out <- if(..2 %in% ..1)
..1
else
c(..1, ..2)
} else {
out <- ..1
}
} else {
out <- ..2
}
out
}
Мы можем ссылаться на отдельные элементы ...
, используя заполнители ..n
; ..1
равно A
и ..2
равно B
. Конечно, foo()
работает только с двумя списками, но не требует этого и не выполняет никаких проверок, просто для простоты. foo()
также должен обрабатывать случаи, когда A
или B
или оба являются character(0)
, что, как я теперь думаю, foo()
делает.
Когда мы используем это в вызове mapply()
, я получаю:
> mapply(foo, A, B)
[[1]]
[1] "JAMES" "JAMES" "RICHARD"
[[2]]
[1] "JOHN" "ROBERT"
[[3]]
[1] "WILLIAM" "MICHAEL" "WILLIAM" "DAVID" "WILLIAM"
[[4]]
[1] "CHARLES"
Версия lapply()
может быть более содержательной, чем абстрактная ..n
, но использует, по сути, тот же код. Вот новая функция, которая работает с A
и B
напрямую, но мы перебираем индексы элементов A
(1, 2, 3, length(A)
), сгенерированные seq_along()
:
foo2 <- function(ind, A, B) {
l1 <- length(A[[ind]])
l2 <- length(B[[ind]])
out <- character(0)
if(l1 > 0) {
if(l2 > 0) {
out <- if(B[[ind]] %in% A[[ind]]) {
A[[ind]]
} else {
c(A[[ind]], B[[ind]])
}
} else {
out <- A[[ind]]
}
} else {
out <- B[[ind]]
}
out
}
Который называется так:
> lapply(seq_along(A), foo2, A = A, B = B)
[[1]]
[1] "JAMES" "JAMES" "RICHARD"
[[2]]
[1] "JOHN" "ROBERT"
[[3]]
[1] "WILLIAM" "MICHAEL" "WILLIAM" "DAVID" "WILLIAM"
[[4]]
[1] "CHARLES"
Похожие вопросы
Новые вопросы
r
R — это бесплатный язык программирования с открытым исходным кодом и программная среда для статистических вычислений, биоинформатики, визуализации и общих вычислений. Пожалуйста, используйте минимально воспроизводимые примеры, которые другие могут запустить с помощью копирования и вставки. Показать желаемый результат полностью. Используйте dput() для данных и укажите все небазовые пакеты с помощью library(). Не вставляйте изображения для данных или кода, вместо этого используйте блоки кода с отступом. Для вопросов по статистике используйте https://stats.stackexchange.com.
dput
.