10

名前付きのリストが 2 つあるとします。

a = list( a=1, b=2, c=list( d=1, e=2 ), d=list( a=1, b=2 ) )
b = list( a=2, c=list( e=1, f=2 ), d=3, e=2 )

これらのリストを再帰的にマージし、2 番目の引数に競合する値が含まれている場合はエントリを上書きしたいと思います。つまり、期待される出力は次のようになります

$a
[1] 2

$b
[1] 2

$c
$c$d
[1] 1

$c$e
[1] 1

$c$f
[1] 2

$d
[1] 3

$e
[1] 2

ヒントはありますか?

4

2 に答える 2

9

ここで独自の再帰関数を作成する必要があると思います。

2つのリストを受け取る関数、list1およびlist2。もしも:

  • list1[[name]]存在するが存在しないlist2[[name]]、使用list1[[name]];
  • list1[[name]]存在するだけでなくlist2[[name]]、両方ともリストではありませんlist2[[name]]。;を使用してください。
  • それ以外の場合は、新しいリストlist1[[name]]を使用して繰り返します。list2[[name]]

何かのようなもの:

myMerge <- function (list1, list2) {
    allNames <- unique(c(names(list1), names(list2)))
    merged <- list1 # we will copy over/replace values from list2 as necessary
    for (x in allNames) {
        # convenience
        a <- list1[[x]]
        b <- list2[[x]]
        if (is.null(a)) {
            # only exists in list2, copy over
            merged[[x]] <- b
        } else if (is.list(a) && is.list(b)) {
            # recurse
            merged[[x]] <- myMerge(a, b)
        } else if (!is.null(b)) {
            # replace the list1 value with the list2 value (if it exists)
            merged[[x]] <- b
        }
    }
    return(merged)
}

警告-マージするリストがおかしい場合、おかしな出力が得られる可能性があります。例えば:

a <- list( a=list(a=1, b=2), b=3 )
b <- list( a=2 )

次に、マージされたリストにはa=2, b=3。これは、リストであっても、b$aからの値がからの値をオーバーライドするためです(この場合に何が起こるかを指定していません)。ただし、これらの種類のケースを処理するように変更するのは簡単です。覚えておいてください-それがリストであるかどうかをテストし、エントリがリストに存在するかどうかを確認するために使用します。a$aa$amyMergeis.listis.null(myList$a)amyList


これが、以下を使用した「ベクトル化」バージョンsapplyです。

merge.lists <- function(a, b) {
    a.names <- names(a)
    b.names <- names(b)
    m.names <- sort(unique(c(a.names, b.names)))
    sapply(m.names, function(i) {
        if (is.list(a[[i]]) & is.list(b[[i]])) merge.lists(a[[i]], b[[i]])
        else if (i %in% b.names) b[[i]]
        else a[[i]]
    }, simplify = FALSE)
}
于 2012-12-11T00:24:43.780 に答える