2012-06-14 2 views
3

У меня есть два длинных списка A и B, которые имеют одинаковую длину, но содержат разные числа эквивалентных элементов:
Список A может содержать много элементов, которые также могут повторяться в одном и том же поле.
В списке В содержится только один элемент или пустое поле, то есть символ (0) ".
A также содержит несколько пустых полей, но для этих записей всегда присутствует элемент, присутствующий в B, поэтому нет записей с пустыми полями в A и B.
Я хочу объединить элементы A и B в новый список той же длины, C, по следующим правилам:Объединить элементы списка?

  • Все элементы из A должны присутствовать на C, включая их потенциальные рецидивы в том же поле.
  • Если B содержит элемент, который еще не присутствует в A той же записи, он также будет добавлен в C.
  • Но если B содержит элемент, который уже присутствует в A той же записи, он будет проигнорирован.
  • Если А имеет пустое поле элемент из В, для этой записи будет добавлен к C.
  • Если B имеет пустое поле элемент (ы) из А, для этой записи будет добавлен к 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)) 

Но удалял рецидивы из А, к сожалению:

> C 
[1] "JAMES" "RICHARD" 
[2] "JOHN" "ROBERT" 
[3] "WILLIAM" "MICHAEL" "DAVID" 
[4] "CHARLES" 
... 

Может кто-нибудь сказать мне, пожалуйста, как совместить эти два списка, сохранить рецидивы от A , и добиться желаемого результата?

спасибо, что заблаговременно!

Update: Машиносчитываемая данные:

A <- list(c("JAMES","JAMES"), 
      c("JOHN","ROBERT"), 
      c("WILLIAM","MICHAEL","WILLIAM","DAVID","WILLIAM"), 
      character(0)) 
B <- list("RICHARD","JOHN",character(0),"CHARLES") 
+1

Не могли бы вы предоставить данные таким образом, чтобы другие люди могли его прочитать? Это поможет им запустить пример, и у них будет больше времени, чтобы найти хорошее решение для вас. Посмотрите здесь, как вы могли это сделать: [SO] (http://stackoverflow.com/questions/5963269/how-to-make-a-great-r-reproducible-example). В частности, посмотрите на 'dput'. –

+0

Большое спасибо за ваш комментарий и совет! В следующий раз я прислушаюсь к этому как можно лучше. – user0815

ответ

7

Вот ваш snippte данных, в воспроизводимой форме:

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" 
+0

Большое спасибо за ваше решение, которое отлично работает! В дополнение к этому благодарю вас за полезное редактирование/обновление моего вопроса. – user0815

Смежные вопросы