合并列表元素?

4

我有两个长列表A和B,它们具有相同的长度但包含不同数量的等效元素:
列表A可以包含许多元素,这些元素也可以在同一字段中重复出现。
列表B只包含一个元素或一个空字段,即“character(0)”。
A还包含一些空字段,但对于这些记录,B中总是存在一个元素,因此A和B中没有空字段的记录。
我想根据以下规则将A和B的元素组合成相同长度的新列表C:

  • 必须在C中包含来自A的所有元素-包括它们在同一字段中可能的重复。
  • 如果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
你能提供数据以便其他人可以轻松阅读吗?这将有助于他们运行示例,并为您找到更好的解决方案节省更多时间。请看这里,了解如何做到这一点:SO。特别是,请查看 dput - Christoph_J
非常感谢您的评论和建议!下次我会尽我所能注意到它。 - user0815
1个回答

7

这里是您的数据片段,以可重复形式呈现:

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()来连接AB列表元素获得了期望的输出,但需要操作提供的向量元素,因此我想出了这个方法:

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占位符来引用...的各个元素;其中..1A..2B。当然,foo()仅适用于两个列表,但不会强制执行此操作或进行任何检查,只是为了保持简单。我现在认为foo()还需要处理AB或两者都是character(0)的情况。
当我们在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更有意义,但使用基本相同的代码。这里是一个新函数,直接使用AB,但我们迭代A元素的索引(由seq_along()生成的1、2、3、length(A)):
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"

非常感谢您的解决方案,它完美地解决了我的问题!除此之外,还要感谢您对我的问题进行的有益编辑和更新。 - user0815

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接