2017-09-29 7 views
3

Je souhaite accomplir la tâche suivante sans avoir à entrer une boucle for, mais plutôt dans une seule commande apply().Coller une liste dans un vecteur, répéter la liste pour chaque niveau de vecteur

J'ai une liste a que je veux répéter N fois, où N est la longueur du vecteur b, coller chaque répétition de a à un élément de b.

Jusqu'à présent, je l'ai fait la MWF suivante:

var <- paste("var", 1:4, sep="") 
treat <- c("A","B") 
spec <- paste("sp", 1:3, sep="") 
a <- combn(var, 2, simplify = FALSE)#this 6 times, for each treatment and species 
b <- do.call(paste, c(expand.grid(treat, spec), sep='.')) 
a1 <- lapply(a, paste, b[1], sep='.') 
a2 <- lapply(a, paste, b[2], sep='.') 
a3 <- lapply(a, paste, b[3], sep='.') 
a4 <- lapply(a, paste, b[4], sep='.') 
a5 <- lapply(a, paste, b[5], sep='.') 
a6 <- lapply(a, paste, b[6], sep='.') 
a.final <- c(a1,a2,a3,a4,a5,a6) 
a.final 

Il serait optimal si je pouvais coller b avant a.

Notez que mes points de départ sont 3 vecteurs: var, treat et spec, alors n'hésitez pas à changer quoi que ce soit à partir de ce point.

Répondre

4

Option 1: Nous pouvons accomplir cela sans aucune boucle apply(). Soit unlist() la liste a, paste() aux valeurs répliquées b, puis relist() basé sur les listes répliquées a. Essayez ceci:

aa <- relist(
    paste(unlist(a), rep(b, each=sum(lengths(a))), sep="."), 
    rep.int(a, length(b)) 
) 

Vérifier:

identical(aa, a.final) 
# [1] TRUE 

Option 1 avec b avant a: Maintenant, pour mettre les b valeurs à l'avant, échanger simplement les arguments dans l'appel paste():

relist(
    paste(rep(b, each=sum(lengths(a))), unlist(a), sep = "."), 
    rep.int(a, length(b)) 
) 

Option 2: Cette option utilise une boucle apply(). Ici, nous utilisons Map() pour faire un collage one-to-one.

ra <- rep(a, length(b)) 
aa2 <- Map(paste, ra, relist(rep(b, each=sum(lengths(a))), ra), sep = ".") 

Vérifier:

identical(aa2, a.final) 
# [1] TRUE 

Option 2 avec b avant a: permuter Juste les Map() anonymes arguments qui sont passés à paste().

ra <- rep(a, length(b)) 
Map(paste, relist(rep(b, each=sum(lengths(a))), ra), ra, sep = ".") 
+0

Ca y est! Merci beaucoup – DaniCee

1

Rester proche de l'approche de l'OP, cela peut être résolu avec imbriqué lapply() en utilisant des fonctions anonymes:

unlist(lapply(b, function(x) lapply(a, function(y) paste(x, y, sep = "."))), 
     recursive = FALSE) 
[[1]] 
[1] "A.sp1.var1" "A.sp1.var2" 

[[2]] 
[1] "A.sp1.var1" "A.sp1.var3" 

[[3]] 
[1] "A.sp1.var1" "A.sp1.var4" 

... 

[[34]] 
[1] "B.sp3.var2" "B.sp3.var3" 

[[35]] 
[1] "B.sp3.var2" "B.sp3.var4" 

[[36]] 
[1] "B.sp3.var3" "B.sp3.var4" 

Note, b est collé devant a. unlist() est nécessaire pour aplatir la liste de premier niveau.

Pour vérifier l'approche fonctionne (a devant b à comparer avec a.final):

identical(a.final, 
      unlist(lapply(b, function(x) lapply(a, function(y) paste(y, x, sep = "."))), 
       recursive = FALSE)) 
[1] TRUE 
1

Ceci est une approche complètement différente qui crée les étiquettes à partir de zéro et les renvoie dans une colonne de 36 lignes x 2 data.table au lieu d'une liste avec 36 vecteurs de longueur 2:

library(data.table) 
# cross join of treat, spec, var. Note, full labels will be created in sprintf() below 
DT <- CJ(LETTERS[1:2], 1:3, 1:4) 
# non equi join as replacement of combn() 
DT[DT, on = .(V1, V2, V3 > V3), nomatch = 0L, 
    # create labels 
    .(sprintf("%s.sp%s.var%i", V1, V2, V3), 
    sprintf("%s.sp%s.var%i", V1, V2, x.V3))] 
  V1   V2 
1: A.sp1.var1 A.sp1.var2 
2: A.sp1.var1 A.sp1.var3 
3: A.sp1.var1 A.sp1.var4 
4: A.sp1.var2 A.sp1.var3 
5: A.sp1.var2 A.sp1.var4 
6: A.sp1.var3 A.sp1.var4 
7: A.sp2.var1 A.sp2.var2 
... 
29: B.sp2.var2 B.sp2.var4 
30: B.sp2.var3 B.sp2.var4 
31: B.sp3.var1 B.sp3.var2 
32: B.sp3.var1 B.sp3.var3 
33: B.sp3.var1 B.sp3.var4 
34: B.sp3.var2 B.sp3.var3 
35: B.sp3.var2 B.sp3.var4 
36: B.sp3.var3 B.sp3.var4 
      V1   V2