D Inicialización de la matriz dinámica, paso y la operación del índice
Pregunta
Lo siento, esto se convirtió en una pregunta de 3 veces sobre las matrices
Creo que las matrices (dinámicas) son realmente poderosas en D, pero lo siguiente me ha estado molestando por un tiempo:
En C ++ podría asignar fácilmente una matriz con valores designados, pero en DI no he encontrado una manera de hacerlo. Seguramente el siguiente no es un problema:
int[] a = new int[N];
a[] = a0;
Pero parece ineficiente, ya que la línea uno se inicializará con 0
, y como 2 con a0
. ¿Podría algo similar a lo siguiente en D?
int[] a = new int(a0)[N]; // illegal
Otra materia de eficiencia que tengo al usar Stride en std.Range:
import std.stdio;
import std.range;
struct S
{
int x;
this(this)
{
writeln("copy ", x);
}
}
void f(S[] s)
{
}
int main()
{
S[] s = new S[10];
foreach (i, ref v; s)
{
v.x = i;
}
f(stride(s, 3)); // error
return 0;
}
¿Seguramente estaba pensando ingenuo que podría simplemente usar Stride para crear una nueva matriz sin copiar sus elementos? No hay forma de hacerlo en D, ¿verdad?
Así que fui y simulé como si la matriz fuera como regresaría, e implementé f
como:
f(s, 3);
void f(S[] s, uint stride)
{
ref S get(uint i)
{
assert (i * stride < s.length);
return s[i * stride];
}
for (uint x ... )
{
get(x) = ...;
}
}
¿Habría una forma de escribir en su lugar Get (x) usando el operador de índice? get[x]
? De esta manera podría mezclar estáticamente / incluir el camino get
función y mantener el resto de la función similar. Me interesaría el enfoque adoptado, ya que una estructura local no puede acceder a las variables de alcance de la función (¿por qué no?).
Solución
Pero parece ineficiente, ya que la línea uno se inicializará con 0 y como 2 con A0. ¿Podría algo similar a lo siguiente en D?
Usar std.array.uninitializedArray
S[] s = uninitializedArray!(S[])(N);
s[] = a0;
¿Seguramente estaba pensando ingenuo que podría simplemente usar Stride para crear una nueva matriz sin copiar sus elementos? No hay forma de hacerlo en D, ¿verdad?
Tu función f
tiene un S[]
Como argumento, que es diferente de lo que stride
devoluciones. La forma de resolver esto es hacer tu f
Función Aceptar cualquier rango haciéndolo una plantilla:
void f(Range)(Range s)
{
foreach (item; s)
// use item
}
S[] s = new S[10];
f(s); // works
f(stride(s, 3)); // works too
Alternativamente, puede copiar la matriz:
f(array(stride(s, 3)));
Pero probablemente desee evitar copiar toda la matriz si es grande.
¿Habría una manera de escribir en su lugar Get (x) usando el operador de índice Get [x]? De esta manera, podría mezclar / incluir estática la función Get Sending y mantener el resto de la función similar. Me interesaría el enfoque adoptado, ya que una estructura local no puede acceder a las variables de alcance de la función (¿por qué no?).
Puede sobrecargar el operador de indexación en su propia estructura.
struct StrideArray
{
this(S[] s, uint stride) { m_array = s; m_stride = stride; }
S opIndex(size_t i) { return s[i * m_stride]; }
void opIndexAssign(size_t i, S value) { s[i * m_stride] = value; }
private S[] m_array;
private uint m_stride;
}
Esta es (más o menos) la forma en que el real stride
funciona la función. Recomiendo leer Rangos.
Otros consejos
Puede duplicar (crear una copia de) una matriz con .dup (esto también funcionará con cortes) o puede establecer los elementos con el inicializador de la matriz
int[] a=a0.dup;
int[] b=[e1,e2,e3];
Puede hacer que el F genérico (stride () devuelva una estructura sobre la que puede iterar, no una matriz)
void f(Z)(Z s)if(isInputRange!Z){
foreach(elem;s){
//...
}
}
Recuerde que las matrices son esencialmente estructuras con un campo de puntero a algún bloque de memoria y un campo de tamaño