简体   繁体   中英

Subtract one from the sum of the first item in a nested list in r

I have an initial nested list (list of lists) of vectors of integers with NA values randomly replacing some integers. Within a nested list, if one vector contains all NA values, it needs to be broken up into two lists (or more, if more than one vector in the nested list contains all NA s). I ultimately need a vector of values that sums the length nested lists minus 1, ie sum(lengths(list[[i]]-1 , where i is the list of vectors in the nested list, and removes any values less than or equal to 0.

So far I have been able to do this, but realized that if a list is 'artificially' broken into 2+ lists, I only need to subtract one from the first position of the nested list. Furthermore, if the first position of the nested list is NA , the subsequent lists in the nested list do not need to be subtracted by 1.

Below is some sample code that provides examples of the full nested list, the nested list with NA values randomly assigned, and the final desired vector of sums for the example lists.

#Full List
L.full<-list(list(1,3,c(0,2,0),c(0,0)),list(1,6,c(0,3,2,0,1,0),c(0,0,0,1,0,0),1,2,c(0,1),2,c(0,0)),
             list(1,0),list(1,0),list(1,4,c(2,0,0,0),c(4,1),c(1,0,0,0,0),0),list(1,0))
#Nested list with "random" NAs
L.miss<-list(list(1,3,c(0,NA,0),c(0,0)),list(1,6,c(0,3,NA,0,NA,0),c(0,NA,0,1,0,0),1,NA,c(0,1),2,c(0,0)),
             list(1,NA),list(1,0),list(1,NA,c(NA,0,0,0),c(NA,NA),c(1,0,0,NA,0),0),list(1,0))
#Desired final output
L.want<-c(5,11,5,1,3,5,1)

The below code may be a bit inelegant but almost gets me where I need to be; it outputs the final vector as [5,11,4,1,2,4,1] , not the desired [5,11,5,1,3,5,1] . How can I have the code subtract one from just the first element in the list, if it is present?

#Break apart 
test<-lapply(lapply(seq_along(L.miss), function(nm) {split(L.miss[[nm]], cumsum(sapply(L.miss[[nm]], function(x) all(is.na(x)))))}), function(lstA) lapply(lstA,function(x) Filter(function(y) !all(is.na(y)), x)))
#Bring the nested list up a level
test2<-unlist(test,recursive=FALSE)
#Remove NA values
test3<-rapply(test2,function(x) x[!is.na(x)], how="replace") #remove NAs
#Sum nested lists
test4<-integer()
for (i in 1:length(test3)){
  test4[i]<-sum(lengths(test3[[i]]))-1
} 
test5<-test4[test4>0] #remove values <=0

Thank you - if this question is too specific for this forum, please let me know and I will remove it.

I think I solved it - it was much simpler to delete the first position in the initial L.miss nested list then ignore the whole "minus 1" altogether:

#Delete first instance
l<-L.miss
for (i in 1:length(l)){
  l[[i]][[1]]<-NULL
}

#Same code as above but for loop sums without -1
test<-lapply(lapply(seq_along(l), function(nm) {split(l[[nm]], cumsum(sapply(l[[nm]], function(x) all(is.na(x)))))}), function(lstA) lapply(lstA,function(x) Filter(function(y) !all(is.na(y)), x)))
test2<-unlist(test,recursive=FALSE)
test3<-rapply(test2,function(x) x[!is.na(x)], how="replace") #remove NAs
test4<-integer()
for (i in 1:length(test3)){
  test4[i]<-sum(lengths(test3[[i]]))
} 
test5<-test4[test4>0] #remove values <=0

#result
#> test5
#[1]  5 11  5  1  3  5  1

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM