Applying a function recursively over a list

140 views Asked by At

I am trying to apply values of a vector over a list of character vectors using lapply and a hand-crafted function that contains multiple for-loops. Argh! Essentially what I have is a list of character vectors that looks like this (filename_lists3):

$`809`
[1] "rakelib/blueprint.rb"          "projects/daedalus/daedalus.rb"

$`859`
[1] "README"
...

and a named, numeric vector that looks like this (degree_list):

projects/daedalus/daedalus.rb          rakelib/blueprint.rb 
                        1                             5 
                   README                  README.mdown 
                        6                             1 
...

What I want to do is to match the character strings in filename_list3 to those in names(degree_list), and when they are the same, replace the character string in filename_list3 with the integer in degree_list.

Here is my code:

dput(filename_lists3[1:10])

structure(list(`809` = c("rakelib/blueprint.rb", "projects/daedalus/daedalus.rb"
), `859` = "README", `957` = "spec/debugger/spec_helper.rb", 
`1007` = c("README.mdown", "README"), `1038` = "spec/ruby/core/file/stat/setgid_spec.rb", 
`1099` = c("vm/test/test_embedding.hpp", "vm/embed.c", "vm/api/embed.h"
), `1179` = c("vm/capi/module.cpp", "kernel/common/module19.rb", 
          "kernel/common/module18.rb"), `1235` = c("vm/builtin/thread.hpp", 
                                                   "vm/builtin/thread.cpp", "kernel/common/thread.rb", "kernel/bootstrap/thread.rb"
          ), `1390` = "spec/ruby/core/marshal/dump_spec.rb", `1422` = c("spec/tags/19/ruby/core/module/constants_tags.txt", 
                                                                        "kernel/common/module19.rb", "kernel/common/module18.rb", 
                                                                        "kernel/common/module.rb")), .Names = c("809", "859", "957", 
                                                                                                                "1007", "1038", "1099", "1179", "1235", "1390", "1422"))

dput(degree_list[1:10])

structure(c(1, 5, 6, 1, 2, 2, 2, 5, 7, 2), .Names = c("projects/daedalus/daedalus.rb", 
                                                  "rakelib/blueprint.rb", "README", "README.mdown", "vm/api/embed.h", 
                                                  "vm/embed.c", "vm/test/test_embedding.hpp", "kernel/common/module18.rb", 
                                                  "kernel/common/module19.rb", "vm/capi/module.cpp"))

as well as the function and the lapply call:

insert_sna_stat <- function(x, input = degree_list){
  for (i in 1:length(x)){
    for (n in 1:length(input))
      if (names(input)[n] == x[i])
        x[i] <- input[n] else 
      x[i] <- x[i]
  }
}

lapply(filename_lists3, insert_sna_stat)

which at this point just generates null. What is going wrong here? How can I modify it to do what I described above?

4

There are 4 answers

0
user1981275 On BEST ANSWER

You can use rapply:

> rapply(filename_lists3, function(x) ifelse(x %in% names(degree_list), degree_list[x], x), how='replace')
$`809`
[1] 5 1

$`859`
[1] 6

$`957`
[1] "spec/debugger/spec_helper.rb"

$`1007`
[1] 1 6

$`1038`
[1] "spec/ruby/core/file/stat/setgid_spec.rb"

$`1099`
[1] 2 2 2

$`1179`
[1] 2 7 5

$`1235`
[1] "vm/builtin/thread.hpp"      "vm/builtin/thread.cpp"     
[3] "kernel/common/thread.rb"    "kernel/bootstrap/thread.rb"

$`1390`
[1] "spec/ruby/core/marshal/dump_spec.rb"

$`1422`
[1] "spec/tags/19/ruby/core/module/constants_tags.txt"
[2] "7"                                               
[3] "5"                                               
[4] "kernel/common/module.rb"  
0
agstudy On

I think you it is better to use merge here. But, first you should transform your lists to data.frames.

D1 <- do.call(rbind,lapply(seq_along(filename_lists),
             function(i) data.frame(name=filename_lists[[i]],
                                    id  = names(filename_lists)[i])))

D2 <- as.data.frame(degree_list)
D2$name <- rownames(D2)

merge(D1,D2,all.x=TRUE)

#                                                name   id degree_list
# 1                     projects/daedalus/daedalus.rb  809           1
# 2                              rakelib/blueprint.rb  809           5
# 3                                            README  859           6
# 4                                            README 1007           6
# 5                      spec/debugger/spec_helper.rb  957          NA
# 6                                      README.mdown 1007           1
# 7           spec/ruby/core/file/stat/setgid_spec.rb 1038          NA
# 8                                    vm/api/embed.h 1099           2
# 9                                        vm/embed.c 1099           2
# 10                       vm/test/test_embedding.hpp 1099           2
# 11                        kernel/common/module18.rb 1179           5
# 12                        kernel/common/module18.rb 1422           5
# 13                        kernel/common/module19.rb 1179           7
# 14                        kernel/common/module19.rb 1422           7
# 15                               vm/capi/module.cpp 1179           2
# 16                       kernel/bootstrap/thread.rb 1235          NA
# 17                          kernel/common/thread.rb 1235          NA
# 18                            vm/builtin/thread.cpp 1235          NA
# 19                            vm/builtin/thread.hpp 1235          NA
# 20              spec/ruby/core/marshal/dump_spec.rb 1390          NA
# 21                          kernel/common/module.rb 1422          NA
# 22 spec/tags/19/ruby/core/module/constants_tags.txt 1422          NA
0
James On

You can lapply over your filename list and use the values to subset the degree list. If there is no match you would get NA, so wrap around and ifelse to return the original values in such cases.

lapply(filename_lists3, function(x) ifelse(is.na(degree_list[x]),x,degree_list[x]))
$`809`
         rakelib/blueprint.rb projects/daedalus/daedalus.rb 
                            5                             1 

$`859`
README 
     6 

$`957`
                          <NA> 
"spec/debugger/spec_helper.rb" 

$`1007`
README.mdown       README 
           1            6 

$`1038`
                                     <NA> 
"spec/ruby/core/file/stat/setgid_spec.rb" 

$`1099`
vm/test/test_embedding.hpp                 vm/embed.c 
                         2                          2 
            vm/api/embed.h 
                         2 

$`1179`
       vm/capi/module.cpp kernel/common/module19.rb kernel/common/module18.rb 
                        2                         7                         5 

$`1235`
                        <NA>                         <NA> 
     "vm/builtin/thread.hpp"      "vm/builtin/thread.cpp" 
                        <NA>                         <NA> 
   "kernel/common/thread.rb" "kernel/bootstrap/thread.rb" 

$`1390`
                                 <NA> 
"spec/ruby/core/marshal/dump_spec.rb" 

$`1422`
                                              <NA> 
"spec/tags/19/ruby/core/module/constants_tags.txt" 
                         kernel/common/module19.rb 
                                               "7" 
                         kernel/common/module18.rb 
                                               "5" 
                                              <NA> 
                         "kernel/common/module.rb"
0
digEmAll On

You can use match function :

res <- lapply(filename_lists3, function(x){
  m <- match(x,names(degree_list))
  x[!is.na(m)] <- degree_list[m[!is.na(m)]]
  return(x)
})

##### results
> res
$`809`
[1] "5" "1"

$`859`
[1] "6"

$`957`
[1] "spec/debugger/spec_helper.rb"

$`1007`
[1] "1" "6"

$`1038`
[1] "spec/ruby/core/file/stat/setgid_spec.rb"

$`1099`
[1] "2" "2" "2"

$`1179`
[1] "2" "7" "5"

$`1235`
[1] "vm/builtin/thread.hpp"      "vm/builtin/thread.cpp"      "kernel/common/thread.rb"    "kernel/bootstrap/thread.rb"

$`1390`
[1] "spec/ruby/core/marshal/dump_spec.rb"

$`1422`
[1] "spec/tags/19/ruby/core/module/constants_tags.txt" "7"                                               
[3] "5"                                                "kernel/common/module.rb"