2010-05-20 15 views
5

Ho una bella lista, che si presenta così:Come accedere agli elementi in un elenco complesso?

tmp = NULL 
t = NULL 
tmp$resultitem$count = "1057230" 
tmp$resultitem$status = "Ok" 
tmp$resultitem$menu = "PubMed" 
tmp$resultitem$dbname = "pubmed" 
t$resultitem$count = "305215" 
t$resultitem$status = "Ok" 
t$resultitem$menu = "PMC" 
t$resultitem$dbname = "pmc" 
tmp = c(tmp, t) 
t = NULL 
t$resultitem$count = "1" 
t$resultitem$status = "Ok" 
t$resultitem$menu = "Journals" 
t$resultitem$dbname = "journals" 
tmp = c(tmp, t) 

che produce:

> str(tmp) 
List of 3 
$ resultitem:List of 4 
    ..$ count : chr "1057230" 
    ..$ status: chr "Ok" 
    ..$ menu : chr "PubMed" 
    ..$ dbname: chr "pubmed" 
$ resultitem:List of 4 
    ..$ count : chr "305215" 
    ..$ status: chr "Ok" 
    ..$ menu : chr "PMC" 
    ..$ dbname: chr "pmc" 
$ resultitem:List of 4 
    ..$ count : chr "1" 
    ..$ status: chr "Ok" 
    ..$ menu : chr "Journals" 
    ..$ dbname: chr "journals" 

Ora voglio per la ricerca negli elementi di ogni resultitem. Voglio conoscere lo dbname per ogni database, che ha meno di 10 count (esempio). In questo caso è molto facile, in quanto questa lista ha solo 3 elementi, ma la lista reale è un po 'più lunga.

Questo potrebbe essere fatto semplicemente con un ciclo for. Ma c'è un modo per farlo con qualche altra funzione di R (come il rapply)? Il mio problema con queste funzioni è che guardano solo un elemento.

Se eseguo un grep per ottenere tutti gli elementi dbname, non riesco a ottenere il conteggio di ciascun elemento.

rapply(tmp, function(x) paste("Content: ", x))[grep("dbname", names(rapply(tmp, c)))]

Qualcuno ha un'idea migliore di un ciclo for?

+6

Perdonami, ma perché stai utilizzando queste strutture di elenco scomode anziché un frame di dati? –

risposta

2

Se siete assolutamente insistente che è necessario farlo in un elenco seguente volontà lavoro per il caso presente.

x <- tmp[sapply(tmp, function(x){x$count>10})] 
str(x) 
(the list items you wanted) 

Più in generale, se si desidera utilizzare effettivamente le liste cenciosi in questo modo è possibile utilizzare lo stesso codice, ma verificare la presenza della voce prima

testForCount <- function(x) {if ('count' %in% names(x)) x$count>10 else FALSE} 
tmp[sapply (tmp, count)] 

Questo funziona per i vostri casi dove gli elenchi non sono della stessa lunghezza e del caso presente. (Continuo a pensare che dovresti usare i frame di dati sia per la velocità che per la rappresentazione sensibile dei dati).

+0

Il problema con i miei dati è che proviene da un webservice. E non è sicuro che esista una colonna. Se il webservice cambia il pacchetto R non funzionerà più. Anche se la query cambia, le colonne potrebbero non essere le stesse di prima. Quindi ho deciso di utilizzare le liste come rappresentazione dei risultati. E ora sto cercando alcuni modi per gestire questi elenchi. Mi hai aiutato molto, grazie. – Martin

+0

Penso che tu stia dicendo che non puoi essere sicuro che la cella esista in una particolare query. Va bene, solo NA quella cella. Se la colonna non esiste affatto, è solo una diversa cornice dati e dovresti comunque adattare il tuo codice. Non sto cercando di rendere la tua vita difficile. Siamo tutti qui cercando di renderti tutto più facile. Nulla di ciò che hai detto preclude un frame di dati. A prescindere da tutto ciò, visto che ti piace aderire alle liste, dovresti contrassegnare la mia come risposta corretta. :) – John

5

R in genere vuole gestire queste cose come data.frames, quindi penso che la soluzione migliore è quella di trasformare la lista in uno (o anche fare un data.frame invece di una lista per cominciare, a meno che non ne abbiate bisogno essere in forma di lista).

x <- do.call(rbind,tmp) 
dat <- data.frame(x) 
dat$count <- as.numeric(dat$count) 

> dat 
    count status  menu dbname 
1 1057230  Ok PubMed pubmed 
2 305215  Ok  PMC  pmc 
3  1  Ok Journals journals 

e quindi per ottenere la risposta (s) è possibile utilizzare le normali operazioni di data.frame sottoinsiemi:

> dat$dbname[dat$count<10] 
$resultitem 
[1] "journals" 
+2

Questo data.frame non è corretto data.frame. Ogni colonna è una lista. Sarà ok se si 'x <-do.call (rbind, lapply (tmp, unlist))' e quindi 'dat <-data.frame (x, stringsAsFactors = FALSE, row.names = NULL)'. – Marek

+0

Ho notato il problema con i nomi delle righe e le colonne sono elenchi, ma non ero sicuro di cosa fare al loro interno. Bella correzione – Fojtasek

+0

Questo funziona perfettamente per il mio esempio, grazie. Ma il problema con i dataframes è che non supportano colonne con lunghezze diverse. E ho altre liste, dove sarà questo il caso. Quindi sono legato alle liste. – Martin

0

Sembra che l'elenco provenga da una struttura XML. È più semplice navigare in XPath e utilizzare la struttura e la funzione di NodeSet getNodeSet nel pacchetto XML

Problemi correlati