Hum, désolé d’avoir une question RTFM, mais j’ai dû mal chercher...
C’est possible pour une fonction de modifier un de ses arguments ?!
Version imprimable
Hum, désolé d’avoir une question RTFM, mais j’ai dû mal chercher...
C’est possible pour une fonction de modifier un de ses arguments ?!
Bonjour,
Je crois deviner ce que tu veux dire, mais pourrais-tu être un peu plus précis sur les contraintes que tu as pour écrire ta fonction, le type d'objet à modifier, etc.
Un petit exemple de test (au moins là où tu en es de tes recherches) serait un plus.
Eh bien, plus précisément... disons que j'ai ça :
Et je voudrais une fonction step2() qui ait la propriété suivante :Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 step <- function(X) { n <- dim(X)[1]; m <- dim(X)[2]; repeat { I <- sample(1:n,2); J <- sample(1:m,2); if(X[I,J][2,1]>0 & X[I,J][1,2]>0) { X[I,J][2,1] <- X[I,J][2,1]-1; X[I,J][1,1] <- X[I,J][1,1]+1; X[I,J][1,2] <- X[I,J][1,2]-1; X[I,J][2,2] <- X[I,J][2,2]+1; break; } } return(X); }
step2(X) a le même effet que X <- step(X).
(edit) mais enfin on s'en fiche, j’aurais pu tout simplement avoir bidule <- function(x) return(x+1); et demander une fonction bidule2() qui incrémente son argument. ;)
Malheureusement - pour autant que je sache - on est obligé de passer par un stockage temporaire de la variable en raison des indices (j'ai jamais trouvé comment utiliser assign() pour des éléments d'une matrice).
La solution est de passer le nom de l'objet (et éventuellement son environnement d'origine à la fonction :
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38 > a <- matrix(rep(0:3, 3), ncol=4) > a [,1] [,2] [,3] [,4] [1,] 0 3 2 1 [2,] 1 0 3 2 [3,] 2 1 0 3 > step2 <- function(x, env=parent.frame()) + { + ## print(env) + X <- get(x, envir=env) + ## print(X) + n <- dim(X)[1] + m <- dim(X)[2] + repeat + { + I <- sample(1:n, 2) + J <- sample(1:m, 2) + if(X[I, J][2, 1] > 0 & X[I, J][1, 2] > 0) + { + X[I, J][2, 1] <- X[I, J][2, 1] - 1 + X[I, J][1, 1] <- X[I, J][1, 1] + 1 + X[I, J][1, 2] <- X[I, J][1, 2] - 1 + X[I, J][2, 2] <- X[I, J][2, 2] + 1 + break + } + } + assign(x, X, envir=env) + } > step2("a") > a [,1] [,2] [,3] [,4] [1,] 0 3 2 1 [2,] 1 0 2 3 [3,] 2 1 1 2
Merci. Malheureusement je ne pense pas gagner en efficacité comme ça...
Effectivement tu ne gagnes ni en terme de mémoire ni en terme d'assignage de variable (lent).
Il y a une autre façon de procéder, un peu plus compliquée, qui est basée sur le fait que les objets dans un environnement peuvent être indexés avec $ :
Le principe est de construire une commande avec paste() (décommente la ligne print... pour un exemple) et de l'évaluer.Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 step2 <- function(x, env=parent.frame()) { X <- paste("env$", x, sep="") repeat { I <- sample(1:nrow(get(x, envir=env)), 2) J <- sample(1:ncol(get(x, envir=env)), 2) if(get(x, envir=env)[I, J][2, 1] > 0 & get(x, envir=env)[I, J][1, 2] > 0) { ## print(paste(X, "[I, J][2, 1] <- ", X, "[I, J][2, 1] - 1", sep="")) eval(parse(text=paste(X, "[I, J][2, 1] <- ", X, "[I, J][2, 1] - 1", sep=""))) eval(parse(text=paste(X, "[I, J][1, 1] <- ", X, "[I, J][1, 1] + 1", sep=""))) eval(parse(text=paste(X, "[I, J][1, 2] <- ", X, "[I, J][1, 2] - 1", sep=""))) eval(parse(text=paste(X, "[I, J][2, 2] <- ", X, "[I, J][2, 2] + 1", sep=""))) break } } }
Si tu travailles sur de grosses matrices et/ou que tu lances la routine un nombre élevé de fois, ça doit valoir le coup.
J'ai lancé un test qui n'est pas encore finit... mais je peux déjà dire que c'est pas du tout vrai :aie:
Ah bin si en fait, il vient de finir (step3 est la dernière fonction):
C'est presque 10x plus long 8OCode:
1
2
3
4
5
6
7
8
9 > a <- matrix(rep(0:3, 3), ncol=4) > system.time(for (i in 1:100000){step2("a")}) utilisateur système écoulé 16.800 0.100 17.592 > > a <- matrix(rep(0:3, 3), ncol=4) > system.time(for (i in 1:100000){step3("a")}) utilisateur système écoulé 123.890 1.700 137.189
Je vais creuser...
Suite et fin (pour l'instant) : les choses les plus simples sont visiblement les meilleurs...
J'ai pas encore regardé côté utilisation de la mémoire...Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141 > Rprof() > a <- matrix(rep(0:3, 3), ncol=4) > for (i in 1:10000){a <- step(a)} > Rprof(NULL) > summaryRprof() $by.self self.time self.pct total.time total.pct "step" 0.70 64.8 1.08 100.0 "sample" 0.36 33.3 0.38 35.2 "==" 0.02 1.9 0.02 1.9 $by.total total.time total.pct self.time self.pct "step" 1.08 100.0 0.70 64.8 "sample" 0.38 35.2 0.36 33.3 "==" 0.02 1.9 0.02 1.9 $sampling.time [1] 1.08 > > Rprof() > a <- matrix(rep(0:3, 3), ncol=4) > for (i in 1:10000){step2("a")} > Rprof(NULL) > summaryRprof() $by.self self.time self.pct total.time total.pct "step2" 0.72 60.0 1.20 100.0 "sample" 0.34 28.3 0.36 30.0 "+" 0.04 3.3 0.04 3.3 "assign" 0.04 3.3 0.04 3.3 ":" 0.02 1.7 0.02 1.7 "&" 0.02 1.7 0.02 1.7 "get" 0.02 1.7 0.02 1.7 $by.total total.time total.pct self.time self.pct "step2" 1.20 100.0 0.72 60.0 "sample" 0.36 30.0 0.34 28.3 "+" 0.04 3.3 0.04 3.3 "assign" 0.04 3.3 0.04 3.3 ":" 0.02 1.7 0.02 1.7 "&" 0.02 1.7 0.02 1.7 "get" 0.02 1.7 0.02 1.7 $sampling.time [1] 1.2 > > Rprof() > a <- matrix(rep(0:3, 3), ncol=4) > for (i in 1:10000){step3("a")} > Rprof(NULL) > summaryRprof() $by.self self.time self.pct total.time total.pct "parse" 1.26 15.1 6.22 74.4 "structure" 0.94 11.2 2.00 23.9 "eval" 0.88 10.5 7.14 85.4 "srcfilecopy" 0.68 8.1 4.02 48.1 "stopifnot" 0.64 7.7 1.10 13.2 "inherits" 0.52 6.2 0.52 6.2 "sample" 0.50 6.0 0.80 9.6 "paste" 0.36 4.3 0.38 4.5 "match" 0.30 3.6 0.90 10.8 "get" 0.26 3.1 0.26 3.1 "step3" 0.18 2.2 8.36 100.0 "identical" 0.18 2.2 0.48 5.7 "getOption" 0.16 1.9 0.30 3.6 "options" 0.14 1.7 0.14 1.7 "sys.parent" 0.12 1.4 0.12 1.4 "nrow" 0.10 1.2 0.14 1.7 "is.factor" 0.08 1.0 0.60 7.2 "match.call" 0.08 1.0 0.28 3.3 "sys.call" 0.08 1.0 0.20 2.4 "names<-" 0.08 1.0 0.08 1.0 "Sys.time" 0.06 0.7 2.06 24.6 "ncol" 0.06 0.7 0.12 1.4 "==" 0.06 0.7 0.06 0.7 "any" 0.06 0.7 0.06 0.7 "as.character" 0.06 0.7 0.06 0.7 "class<-" 0.06 0.7 0.06 0.7 "is.character" 0.06 0.7 0.06 0.7 "is.na" 0.06 0.7 0.06 0.7 "isTRUE" 0.04 0.5 0.52 6.2 "new.env" 0.04 0.5 0.06 0.7 "!" 0.04 0.5 0.04 0.5 "list" 0.04 0.5 0.04 0.5 "parent.frame" 0.04 0.5 0.04 0.5 "stdin" 0.04 0.5 0.04 0.5 "%in%" 0.02 0.2 0.48 5.7 ":" 0.02 0.2 0.02 0.2 "all" 0.02 0.2 0.02 0.2 "emptyenv" 0.02 0.2 0.02 0.2 "length" 0.02 0.2 0.02 0.2 $by.total total.time total.pct self.time self.pct "step3" 8.36 100.0 0.18 2.2 "eval" 7.14 85.4 0.88 10.5 "parse" 6.22 74.4 1.26 15.1 "srcfilecopy" 4.02 48.1 0.68 8.1 "Sys.time" 2.06 24.6 0.06 0.7 "structure" 2.00 23.9 0.94 11.2 "stopifnot" 1.10 13.2 0.64 7.7 "match" 0.90 10.8 0.30 3.6 "sample" 0.80 9.6 0.50 6.0 "is.factor" 0.60 7.2 0.08 1.0 "inherits" 0.52 6.2 0.52 6.2 "isTRUE" 0.52 6.2 0.04 0.5 "identical" 0.48 5.7 0.18 2.2 "%in%" 0.48 5.7 0.02 0.2 "paste" 0.38 4.5 0.36 4.3 "getOption" 0.30 3.6 0.16 1.9 "match.call" 0.28 3.3 0.08 1.0 "get" 0.26 3.1 0.26 3.1 "sys.call" 0.20 2.4 0.08 1.0 "options" 0.14 1.7 0.14 1.7 "nrow" 0.14 1.7 0.10 1.2 "sys.parent" 0.12 1.4 0.12 1.4 "ncol" 0.12 1.4 0.06 0.7 "names<-" 0.08 1.0 0.08 1.0 "==" 0.06 0.7 0.06 0.7 "any" 0.06 0.7 0.06 0.7 "as.character" 0.06 0.7 0.06 0.7 "class<-" 0.06 0.7 0.06 0.7 "is.character" 0.06 0.7 0.06 0.7 "is.na" 0.06 0.7 0.06 0.7 "new.env" 0.06 0.7 0.04 0.5 "!" 0.04 0.5 0.04 0.5 "list" 0.04 0.5 0.04 0.5 "parent.frame" 0.04 0.5 0.04 0.5 "stdin" 0.04 0.5 0.04 0.5 ":" 0.02 0.2 0.02 0.2 "all" 0.02 0.2 0.02 0.2 "emptyenv" 0.02 0.2 0.02 0.2 "length" 0.02 0.2 0.02 0.2 $sampling.time [1] 8.36
Mais bon, bref, pour des calculs vraiment efficaces avec des passages par adresse, je crains qu'il ne faille coder en C (voir le manuel writting R extensions).
Merci beaucoup !! J'étais pas revenu après ta réponse précédente...