¿Por qué es malo usar asignar?
Esta publicación ( Evaluación diferida en R: ¿se ve afectada la asignación? ) cubre algunos puntos en común, pero no estoy seguro de que responda mi pregunta.
Dejé de consumir assign
cuando descubrí la apply
familia hace bastante tiempo, aunque sea por pura cuestión de elegancia en situaciones como esta:
names.foo <- letters
values.foo <- LETTERS
for (i in 1:length(names.foo))
assign(names.foo[i], paste("This is: ", values.foo[i]))
que puede ser reemplazado por:
foo <- lapply(X=values.foo, FUN=function (k) paste("This is :", k))
names(foo) <- names.foo
Esta es también la razón por la que esto ( http://cran.r-project.org/doc/FAQ/R-FAQ.html#How-can-I-turn-a-string-into-a-variable_003f ) R-faq dice que esto debería evitarse.
Ahora, sé que eso assign
generalmente está mal visto. ¿Pero hay otras razones que no sé? Sospecho que puede afectar el alcance o la evaluación diferida, pero no estoy seguro. El código de ejemplo que demuestre tales problemas será excelente.
En realidad esas dos operaciones son bastante diferentes. El primero te ofrece 26 objetos diferentes mientras que el segundo solo te ofrece uno. El segundo objeto será mucho más fácil de utilizar en los análisis. Entonces, supongo que diría que ya ha demostrado la principal desventaja de assign
, es decir, la necesidad de tener que usarlo siempre get
para acorralar o reunir todos los objetos individuales con nombres similares que ahora están "sueltos" en el entorno global. Intenta imaginar cómo harías cualquier cosa en serie con esos 26 objetos separados. Una simple lapply(foo, func)
será suficiente para la segunda estrategia.
Esa cita de preguntas frecuentes en realidad solo dice que usar la asignación y luego asignar nombres es más fácil, pero no implica que sea "malo". Lo leo como "menos funcional", ya que en realidad no devuelve un valor asignado. El efecto parece ser un efecto secundario (y en este caso la assign
estrategia resulta en 26 efectos secundarios separados). El uso de assign
parece ser adoptado por personas que provienen de lenguajes que tienen variables globales como una forma de evitar adoptar el "True R Way", es decir, programación funcional con objetos de datos. Realmente deberían aprender a usar listas en lugar de llenar su espacio de trabajo con elementos con nombres individuales.
Existe otro paradigma de asignación que se puede utilizar:
foo <- setNames( paste0(letters,1:26), LETTERS)
Eso crea un vector atómico con nombre en lugar de una lista con nombre, pero el acceso a los valores en el vector todavía se realiza con los nombres dados a [
.
Como fuente fortune(236)
pensé en agregar un par de ejemplos (ver también fortune(174)
).
Primero, una prueba. Considere el siguiente código:
x <- 1
y <- some.function.that.uses.assign(rnorm(100))
Después de ejecutar las 2 líneas de código anteriores, ¿cuál es el valor de x
?
La assign
función se utiliza para realizar "Acción a distancia" (consulte http://en.wikipedia.org/wiki/Action_at_a_distance_(computer_programming) o busque en Google). Esta es a menudo la fuente de errores difíciles de encontrar.
Creo que el mayor problema assign
es que tiende a llevar a las personas por caminos de pensamiento que las alejan de mejores opciones. Un ejemplo simple son los 2 conjuntos de códigos de la pregunta. La lapply
solución es más elegante y debería promoverse, pero el mero hecho de que la gente conozca la assign
función los lleva a la opción del bucle. Luego deciden que necesitan hacer la misma operación en cada objeto creado en el bucle (lo que sería simplemente otra solución simple lapply
o sapply
si se usara la solución elegante) y recurren a un bucle aún más complicado que involucra ambos get
y apply
junto con feas llamadas a paste
. Entonces los enamorados assign
intentan hacer algo como:
curname <- paste('myvector[', i, ']')
assign(curname, i)
Y eso no hace exactamente lo que esperaban, lo que lleva a quejarse de R (lo cual es tan justo como quejarse de que la casa de mi vecino de al lado está demasiado lejos porque elegí caminar el camino más largo alrededor de la cuadra) o, peor aún, a profundizar. en usar eval
y parse
hacer que su cadena construida "funcione" (lo que luego conduce a fortune(106)
y fortune(181)
).
Me gustaría señalar que assign
debe usarse con environment
s.
Desde ese punto de vista, lo "malo" del ejemplo anterior es utilizar una estructura de datos no del todo apropiada (el entorno base en lugar de a list
o data.frame
, vector
, ...).
Nota al margen: también para environment
s, los operadores $
y $<-
funcionan, por lo que en muchos casos lo explícito assign
y get
tampoco es necesario allí.