2011-08-01 58 views
4

根據手冊,Filter作品的載體,和它發生也工作在列表,例如:在R中,如何過濾列表列表?

z <- list(a=1, b=2, c=3) 
Filter(function(i){ 
    z[[i]] > 1 
}, z) 
$b 
[1] 2 

$c 
[1] 3 

但是,它並沒有在列表的列表,如:

z <- list(z1=list(a=1,b=2,c=3), z2=list(a=1,b=1,c=1), z3=list()) 
Filter(function(i){ 
    if(length(z[[i]])>0){ 
    if(z[[i]]$b > 1) 
     TRUE 
    else 
     FALSE 
    } 
    else 
    FALSE 
}, z) 
Error in z[[i]] : invalid subscript type 'list' 
工作

然後過濾不使用嵌套循環列表的最佳方式是什麼?它也可能是列表的列表清單...

(我試圖與嵌套lapply的替代,但無法管理,使其工作。)

編輯:在第二個例子中,這裏是我想要的東西來獲得:

list(z1=list(a=1,b=2,c=3)) 

的是,毫無Z $ Z2因爲Z $ Z2 $ b < 1,沒有Z $ Z3,因爲它是空的。

+2

你試過'rapply'嗎? – Iterator

+0

@Iterator:是的,謝謝,但我沒有設法獲得我想要的輸出(看我的編輯) – tflutre

+0

奇怪的是:別人在這裏發佈了一個答案,現在它消失了。不過,我不知道它解決了什麼問題。 – Iterator

回答

0

這裏美是沒有索賠,並沒有做深度搜索:

z2 <- lapply(z, function(x){ if("b" %in% names(x) && x[["b"]] >1) x else {} }) 
z2[unlist(lapply(z2, is.null))] <- NULL 

> z2 
$z1 
$z1$a 
[1] 1 

$z1$b 
[1] 2 

$z1$c 
[1] 3 

編輯:此代碼將遍歷一個列表,並裝配有「B」> 1的節點它需要一些工作正確標記節點。首先一個更深層次的嵌套列表:

z <- list(z1=list(a=1,b=2,c=3), z2=list(a=1,b=1,c=1), z3=list(), 
      z4 = list(z5=list(a=5,b=6,c=7), z6=list(a=7,b=8,c=9))) 

checkbGT1 <- function(ll){ root <- list() 
      for(i in seq_along(ll)) {if ("b" %in% names(ll[[i]]) && ll[[i]]$b >1) { 
           root <- c(root, ll[[i]]) 
           }else{ 
           if( length(ll[[i]]) && is.list(ll[[i]])) 
            { root <- c(root, list(checkbGT1(ll[[i]]))) } 
              } 
             } 
        return(root) } 
+0

謝謝,您的解決方案適用於我提供的示例,但對列表列表等不易擴展。無論如何,如果沒有更好的答案,我會接受您的答案。 – tflutre

+0

我認爲遞歸答案是可能的。我甚至可以複製這種答案的結構,但是我很難填充節點。我會等待。 –

1

我從來沒有對你的問題之前使用Filter,所以這是早上:)一個很好的鍛鍊第一件事

至少有幾件事情這會讓你失望(我想)。

讓我們先從你的第一個簡單的匿名函數,但讓我們把它獨立,以便更容易閱讀:

f <- function(i){ 
     z[[i]] > 1 
    } 

它應該在你跳出這個函數有一個參數,i,但在功能它叫z。這不是很好的「功能性」的編程:)

所以通過改變功能開始:

f <- function(i){ 
     i > 1 
    } 

,你會看到Filter將實際運行對列表的列表:

z <- list(z1=list(a=1,b=2,c=3), z2=list(a=1,b=1,c=1)) 
Filter(f, z) 

但它返回:

> Filter(f, z) 
$z2 
$z2$a 
[1] 1 

$z2$b 
[1] 1 

$z2$c 
[1] 1 


$<NA> 
NULL 

這不完全是你想要的。老實說,我不能饒舌爲什麼它返回的結果,也許有人可以向我解釋。

@DWin說他應該有一個遞歸的解決方案時,他正在吠叫正確的樹。我砍死了第一個嘗試在一個遞歸函數,但你需要加以改進:

fancyFilter <- function(f, x){ 
    if (is.list(x[[1]])) #only testing the first element... bad practice 
    lapply(x, fancyFilter, f=f) #recursion FTW!! 
    else 
    return(lapply(x, Filter, f=f)) 
} 

fancyFilter看着傳遞給它的x的第一個元素,如果該元素是一個列表,它遞歸請在列表的每個元素上調用fancyFilter。但是,如果元素#2不是列表呢?這就是你應該測試的東西,並且挑出它對你是否重要。但fancyFilter結果似乎看起來像你所追求的:

> fancyFilter(f, z) 
$z1 
$z1$a 
numeric(0) 

$z1$b 
[1] 2 

$z1$c 
[1] 3 


$z2 
$z2$a 
numeric(0) 

$z2$b 
numeric(0) 

$z2$c 
numeric(0) 

您可能需要添加一些邏輯來清理輸出使FALSE結果沒有得到調戲到numeric(0)。而且,顯然,我僅使用簡單函數做了一個例子,而不是第二個例子中使用的更復雜的函數。

+0

非常感謝!我設法在2層列表上使用了精美版本的答案,但它不適用於3層列表。結果,我得到一個空的「名單」,我不知道那是什麼...但是,因此不允許我提出一個新問題。我應該先接受你的回答嗎? – tflutre

3

我認爲你應該使用:

Filter(function(x){length(x)>0 && x[["b"]] > 1},z) 

謂詞(使用的是過濾z上的功能)適用於z的元素,而不是他們的索引。