Te traemos la respuesta a esta dificultad, al menos eso creemos. Si presentas preguntas coméntalo y sin tardanza
Solución:
Uso general
Esto es lo que pienso
- Usando cadenas y posteriormente
ToString
–ToExpression
solo generar nombres de variables es bastante inaceptable, o al menos debería ser lo último que intente. No conozco un solo caso en el que esto no pueda reemplazarse con una mejor solución - El uso de subíndices también es bastante malo y debe evitarse, excepto con fines puramente de presentación, como señaló.
-
Para los casos en los que necesita utilizar muchas variables generadas, las variables indexadas suelen ser la mejor manera de hacerlo. Suelen tomar la forma
head[index]
y puede usarse en la mayoría de los lugares donde se pueden usar variables habituales, particularmente en ecuaciones u otras expresiones de naturaleza simbólica (inerte). Necesita un poco más de cuidado con las variables indexadas que con los símbolos simples, en particular, es mejor asegurarse de que
index
es numérico o, si es una expresión, debe ser inerte en el sentido de evaluación (mantener el mismo valor siempre o ningún valor). -
A veces, también puede utilizar los símbolos generados mediante el uso de
Unique[...]
. Por lo general, se utilizan como marcadores de posición anónimos temporales en algunas transformaciones intermedias, pero luego deberá asegurarse de que se destruyan cuando ya no los necesite.
Asignaciones y estado
Un aspecto muy importante aquí es si las variables están destinadas a ser entidades simbólicas inertes o si planea almacenar algunos valores en ellas. A continuación, se indican algunas cosas a tener en cuenta:
-
Los valores almacenados en variables se almacenarán en diferentes tipos de reglas para variables de símbolo y variables indexadas:
- Para las variables basadas en símbolos, estos estarán en
OwnValues
- Para las variables indexadas, estas estarán en
DownValues
, o algunas vecesSubValues
, si usa índices anidados.
- Para las variables basadas en símbolos, estos estarán en
-
Solo los símbolos permiten asignaciones de piezas. Entonces, por ejemplo, puedes hacer
a = Range[10]; a[[5]] = 100;
pero no puedes hacer
a[1]=Range[10]; (* Ok by itself *) a[1][[5]] = 100 (* Won't work *)
Esto puede ser un gran problema para algunas aplicaciones.
-
Solo los símbolos pueden servir como variables / constantes locales en
Module
,Block
,With
,Function
,Pattern
etc. -
Para el caso de muchas variables, las variables indexadas pueden ser más fáciles de administrar, ya que solo debe borrar un símbolo.
-
Para borrar selectivamente una variable indexada dada, debe usar
Unset
, noClear
:a[1]=.
-
Las variables indexadas no se pueden usar dentro
Compile
, aunque puede aparecer que pueden. -
Si debe realizar asignaciones a muchas variables (indexadas), consideraría usar un
Association
en lugar de. Esto puede facilitarlo desde el punto de vista de la gestión de recursos, ya que puede almacenar una asociación en una sola variable. Una ventaja adicional es que, entonces, se permiten asignaciones de partes a variables indexadas particulares:assoc = <|a -> 1, 2, 3, b -> 4, 5, 6|>; assoc[[Key[a], 2]] = 10; assoc (* <|a -> 1, 10, 3, b -> 4, 5, 6|> *)
Notas
Por lo que puedo recordar ahora, siendo AtomQ
no es un requisito para la mayoría de los usos de variables. Siendo un llano Symbol
se requiere en algunos casos, como para variables locales en construcciones de alcance, o asignaciones de partes, como expliqué anteriormente.
En general, mi experiencia es que la mayoría de los usos de las variables indexadas en el contexto de programación pura son más o menos equivalentes al uso de una tabla hash. En el contexto de las manipulaciones simbólicas, las variables indexadas pueden ser bastante útiles de muchas formas: pueden representar, por ejemplo, coeficientes de potencias en un polinomio y muchas otras cosas.
Para cualquier cosa que involucre programación / transformaciones, me mantendría alejado de Subscript
, Notation`
, Symbolize
, y todas las demás cosas que pueden mezclar aspectos de evaluación y presentación. Usarlos en código es solo una invitación a problemas. Si desea formatear una expresión de alguna manera, escriba funciones especiales que lo harían, como una etapa separada.
Utilizando DownValues
le permite formatear la pantalla en el formulario con subíndice sin usar Notation
y Symbolize
(Format[#[n_]] := Subscript[#, n]) & /@ x, σ, a;
kvar[k_] := Through[x, σ, a[k]]
kvar[3]
kvar[n]
Si nunca va a utilizar un índice simbólico, puede restringir el argumento de kvar
para Integer
como lo hizo originalmente.
¿Cuáles son los requisitos para las variables de buen comportamiento?
Las funciones no son variables, aunque en la mayoría de los casos, el kernel trata las variables y funciones indefinidas de manera idéntica. A veces no es así. Después de todo, hay están lugares en matemáticas donde la diferencia entre un número y una función es importante.
Un ejemplo extremo e indocumentado es Dt[]
, la función derivada total. Allí,f[1]
es muy diferente de f1
. f[1]
es un número, el valor de f
en 1, constante por definición de una función matemática de una variable, mientras f1
no se supone que sea constante a menos que se haga una declaración explícita.
f[1] f[1]
Head[f[1]] f
AtomQ[f[1]] False
Dt[f[x], x] f'[x]
Dt[f[y], x] Dt[y, x] f'[y]
Dt[f[1], x] 0
Dt[f1, x] Dt[f1, x]
D[f[1], x] 0
¿Cuál es la forma recomendada y más elegante de variables indexadas?
Un método muy simple es hacer esta definición para cada variable indexada:
x[i_Integer] := x[i] = With[u = Unique[x], Format[u] = Subscript[x, i]; u]
O,
defineIndexedVariable[x_Symbol] := (
x[i_Integer] := x[i] = With[u = Unique[x], Format[u] = Subscript[x, i]; u]
)
Permite subíndices negativos, no usa Symbol
, y Unique[x]
manejas Context
correctamente, pero InputForm[Array[x,5]]
impresiones (decir) x$2136, x$2152, x$2163, x$2164, x$2165
. No hay tentación de escribir a veces x[1]
y a veces escribir x$2136
.
Otro método más complicado de construir símbolos sobre la marcha es bueno, no muy elegante, y es un ejemplo de cómo las cosas complicadas pueden colapsar repentinamente en la simplicidad, pero evita la repetición. string operaciones y problemas con $Context
. Nos permite escribir v[1]
y que se imprima como Subscript[v, 1]
(que muestra $ text v _1 $) y tienen InputForm[v[1]], Head[v[1]], AtomQ[v[1]]
evaluar a v⎵1, Symbol, True
. InputForm[Array[v,5]]
huellas dactilares v⎵1, v⎵2, v⎵3, v⎵4, v⎵5
, y a veces podemos escribir v[1]
y aveces v⎵1
.
Simplemente pegue esta función en su cuaderno y evalúela para cada símbolo indexado. Cada subíndice entero no negativo evaluará la función del símbolo exactamente una vez. La primera versión evalúa el contexto[FUN]<> SymbolName[FUN] cada vez que se encuentra un nuevo subíndice.
defineIndexedVariable[FUN_Symbol] :=
FUN[ix_Integer /; ix ≥ 0] := With[
v=Symbol[Context[FUN]<>SymbolName[FUN]<>"⎵"<>ToString[ix]]
,
Format[v] = Subscript[FUN,ix];
FUN[ix] = v
]
Para un símbolo, optimícelo a mano y especifique el contexto explícitamente en todas partes:
FUN`FUN[ix_Integer /; ix ≥ 0] := With[
v=Symbol["FUN`FUN⎵"<>ToString[ix]]
,
Format[v] = Subscript[FUN`FUN,ix];
FUN`FUN[ix] = v
]
O obtenga la misma optimización con esta versión:
defineIndexedVariable[FUN_Symbol] := With[
prefix = Context[FUN] <> SymbolName[FUN] <> "⎵"
,
FUN[ix_Integer /; ix >= 0] := With[
v = Symbol[prefix <> ToString[ix]]
,
Format[v] = Subscript[FUN, ix];
FUN[ix] = v
]
]
los Context[FUN]
prefix asegura que todos los nuevos símbolos estarán en el mismo contexto que la definición de la función. los FUN[ix] =
memoriza la función para Symbol
se llama sólo una vez para cada índice distinto, y el Format[v]
la definición se hace una sola vez. La ausencia de un punto y coma después del FUN[ix] = v
es absolutamente esencial.
Después defineIndexedVariable[v]
, obtenemos (OutputForm
en una terminal de texto)
v
v[1] 1
Head[v[1]] Symbol
AtomQ[v[1]] True
Dt[v[x], x] v'[x]
Dt[v[y], x] Dt[y, x] v'[y]
Dt[v , x]
Dt[v[1], x] 1
Dt[v1, x] Dt[v1, x]
D[v[1], x] 0
Information["v"]
:
Global`v
v[1] = v⎵1
v[ix$_Integer/;ix$>=0]:=With[v$=Symbol["Global`v⎵"<>ToString[ix$]],Format[v$]=Subscript[v,ix$];v[ix$]=v$]
Usando la interfaz estándar, ?? v no se muestrav⎵1
. Pero InputForm[Array[x,5]]
huellas dactilares v⎵1, v⎵2, v⎵3, v⎵4, v⎵5
Código que imprimió las tablas anteriores:
Function[x,Table[" ",Length[x]],HoldForm/@Unevaluated[x],x, HoldAll][v[1],InputForm[v[1]],Head[v[1]],AtomQ[v[1]],Dt[v[x],x],Dt[v[y],x],Dt[v[1],x],Dt[v1,x],D[v[1],x]]//Transpose//TableForm//Print
Si tienes alguna perplejidad y disposición de desarrollar nuestro post puedes ejecutar una explicación y con deseo lo observaremos.