Write list comprehensions in R!
The eList package allows users to write vectorizedforloops and contains a variety of tools for working with lists and othervectors. Just wrap a normalfor loop within one of thecomprehension functions, such asList(), and let thepackage do the rest.
Features include, but are not limited to:
"." toseparate names.if,else statements to filterresults.=., clust = and thecluster.enum anditems toaccess the index or name within the loop, orzip objectstogether.for loops.List(...) orList[...] for thecomprehension.. notation forvariables) or calls.You can install the released version of eList fromCRAN with:
install.packages("eList")A simple “list” comprehension that accumulates all integer sequencesto 4 using theList function. Though it looks like afor loop, it is actually usinglapply behindthe scenes.
library(eList)#>#> Attaching package: 'eList'#> The following object is masked from 'package:stats':#>#> filter#> The following object is masked from 'package:utils':#>#> zipList(for (iin1:4)1:i)#> [[1]]#> [1] 1#>#> [[2]]#> [1] 1 2#>#> [[3]]#> [1] 1 2 3#>#> [[4]]#> [1] 1 2 3 4Loops can be nested and filtered usingif statements.The example below usesNum to produce a numeric vectorrather than a list. Other comprehensions includeChr forcharacter vectors,Logical for logical vectors,Vec for flat(non-list) vectors, etc.
Num(for (iin1:4)for (jin3:6)if (i== j) i^2)#> [1] 9 16Use the “dot” notation to use multiple variables within the loop.
Chr(for (i.jinzip(1:4,5:8))paste0(i, j))#> [1] "15" "26" "37" "48"Use= within the loop to assign a name to each itemwithin the list, or other item.
values<-zip(letters[1:4],5:8)List(for (i.jin values)i = j)#> $a#> [1] "5"#>#> $b#> [1] "6"#>#> $c#> [1] "7"#>#> $d#> [1] "8"Parallelization is also very easy. Just create a cluster and add itto the comprehension with theclust argument.
my_cluster<-auto_cluster()x<-Num(for (iinsample(1:100,50))sqrt(i),clust = my_cluster)# Close the cluster if not needed!close_cluster(my_cluster)x#> [1] 3.872983 9.949874 3.316625 6.633250 7.000000 9.165151 9.899495 9.539392#> [9] 9.055385 3.464102 5.830952 9.486833 3.741657 8.660254 4.898979 8.000000#> [17] 4.690416 5.477226 5.385165 5.000000 8.485281 8.246211 4.358899 7.416198#> [25] 8.717798 9.591663 9.433981 7.549834 3.162278 9.797959 7.615773 3.000000#> [33] 9.746794 2.236068 5.291503 8.124038 9.219544 9.695360 7.483315 9.643651#> [41] 3.605551 4.000000 1.732051 5.196152 2.828427 6.855655 7.681146 7.348469#> [49] 7.211103 7.280110Want a statistical summary using a comprehension? eList contains avariety of summary functions for that purpose.Stats is ageneral summary comprehension that computes many different values.
Stats(for (iinsample(1:100,50))sqrt(i))#> $min#> [1] 2#>#> $q1#> [1] 6.143211#>#> $med#> [1] 7.483016#>#> $q3#> [1] 8.587745#>#> $max#> [1] 10#>#> $mean#> [1] 7.172598#>#> $sd#> [1] 2.028831eList also contains functional programming style functions forworking with lists and other vectors. These functions perform anoperation using a function on another object. They are similar to thehigher order functions in Base R, but are pipe-friendly, handle a wideranger of object types, and allow for different methods of specifyingfunctions.
x<-list(1:4,5:8,9:12)map(x, mean)#> [[1]]#> [1] 2.5#>#> [[2]]#> [1] 6.5#>#> [[3]]#> [1] 10.5This can also be calculated using formula notation. Formulas can bebe written as either a two-sided formula or a one-sided formula byprefixing variables with dots.
# Two-sided Formulamap(x, i~sqrt(i)+1)#> [[1]]#> [1] 2.000000 2.414214 2.732051 3.000000#>#> [[2]]#> [1] 3.236068 3.449490 3.645751 3.828427#>#> [[3]]#> [1] 4.000000 4.162278 4.316625 4.464102# One-sided Formulamap(x,~sqrt(.i)+1)#> [[1]]#> [1] 2.000000 2.414214 2.732051 3.000000#>#> [[2]]#> [1] 3.236068 3.449490 3.645751 3.828427#>#> [[3]]#> [1] 4.000000 4.162278 4.316625 4.464102The higher order functions also accept unevaluated “calls”.
round2<-substitute(round(digits=2))map(rnorm(5), round2)#> [[1]]#> [1] 0.16#>#> [[2]]#> [1] -3.18#>#> [[3]]#> [1] -0.17#>#> [[4]]#> [1] -0.13#>#> [[5]]#> [1] -0.27