2012-03-29 17 views
7

Considere el siguiente código:D2: la asignación de rangos/iteradores a rodajas de matriz

enum size = 16; 
double[size] arr1 = [...]; 
double[size] arr2 = [...]; 
process = (double x) { return (x + 1); }; 

arr2[] = map!(process)(arr1[]); // here 

tengo problemas para convertir los resultados de map volver a mi array plano. El problema se aplica no solo a map, sino también a take, repeat y todas esas herramientas de std.algorithm y std.range que operan en rangos.

En esta tarea, obtengo Error: cannot implicitly convert expression (map(arr1[])) of type Result to double[]. ¿Cómo puedo evaluar range to array sin usar

uint i = 0; 
foreach (x; map!(process)(arr1[])) { 
    arr2[i] = x; 
    i++; 
} 

?

Además, ¿alguien puede explicar por qué debo llamar al map!(process)(arr1[]) en lugar de map!(process)(arr1) con matrices estáticas? ¿No deberían las matrices estáticas ser compatibles con la dinámica para los medios de iteración, o no obtengo algo?

Además, parece que la sintaxis de enumeración directa foreach (index, item; sequence) no funciona para los rangos: ¿hay soluciones? Supongo que el motivo es el mismo que explica por qué los rangos no se pueden asignar a las divisiones de la matriz.

Respuesta

11

Funciones tales como map y filter rangos de cambio, ni matrices, por lo que simplemente la asignación a una matriz no va a trabajar más de lo que la asignación de un string a wstring se va a trabajar. Son diferentes tipos. Y para muchas funciones basadas en rango (incluyendo map y filter), los rangos que devuelven son realmente flojos para evitar cálculos innecesarios, lo que los hace mucho menos compatibles con una matriz. La solución es usar std.array.array, que toma un rango y crea una matriz dinámica a partir de él. Así, se podría hacer

auto arr = array(map!process(origArray)); 

Sin embargo, aconsejaría no convertir un rango en una matriz antes de que realmente necesita, ya que puede dar lugar a cálculos innecesarios, y significa la asignación de una nueva matriz. Si realmente necesita una matriz, entonces, por supuesto, use std.array.array para convertir el rango, pero operar en el rango a menudo puede ser más eficiente si no necesita una matriz real. Sin embargo, si desea convertir el resultado en una matriz estática en oposición a una dinámica, probablemente sea mejor simplemente asignar cada elemento en un bucle (y tal vez omitiendo map en total), ya que usando std.array.array entonces habrá asignado una matriz dinámica que no usará una vez que haya asignado la matriz estática. Es un desperdicio de memoria.

Además, tenga en cuenta que el uso de matrices estáticas con funciones basadas en rangos puede ser riesgoso ya que debe dividir la matriz estática para obtener una matriz dinámica para que las funciones basadas en rango puedan procesar y si esa matriz dinámica escapa del alcance que la matriz estática fue declarada, entonces estás perdiendo referencias a datos que ya no existen. Por ejemplo,

auto func() 
{ 
    int[5] arr; 
    return map!process(arr[]); 
} 

sería muy malo. Sin embargo, mientras haya terminado de usar la porción y ya no se haga referencia a ella (incluidos los intervalos que podrían haberse creado) antes de salir del alcance con la matriz estática, no debería preocuparse. Es es algo de lo que tener cuidado.

En cuanto a la cuestión de tener que cortar las matrices estáticas, que realmente debería preguntarse que como una cuestión separada, pero dos preguntas existentes que se relacionan con ella son this one y this one. Lo que básicamente se reduce a que IFTI (instanciación de plantilla de función implícita) ejemplifica el uso del tipo exacto que se le da, y una matriz estática no es ni una matriz dinámica ni un rango, por lo que cualquier función que requiera específicamente una matriz dinámica o una rango no podrá compilar con una matriz estática. El compilador dividirá implícitamente matrices estáticas para convertirlas en matrices dinámicas para funciones que toman explícitamente matrices dinámicas, pero ese tipo de conversiones implícitas no ocurren con la creación de instancias de plantilla, por lo que debe dividir explícitamente las matrices estáticas para pasarlas a rango- funciones basadas

En cuanto a la pregunta sobre el uso de foreach con índices e intervalos, nuevamente, no debería hacer muchas preguntas en la misma pregunta. Por favor, envíe preguntas por separado para cada pregunta que tenga. Lo que se reduce a es que aunque

foreach(elem; range) 
{ 
    //stuff 
} 

consigue bajó a algo cercano a

for(; !range.empty; range.popFront()) 
{ 
    auto elem = range.front; 
    //stuff 
} 

Y eso no implica índices en absoluto. Es podría cambiar para crear una variable de índice para usted, pero no siempre tiene sentido que los rangos tengan su índice iterando por uno así en cada iteración (por mucho que generalmente estaría bien), y eso no lo ha hecho no se ha hecho. Sin embargo, es bastante simple agregar tu propio contador.

{ 
    size_t i; 
    foreach(elem; range) 
    { 
     //stuff 
     ++i; 
    } 
} 

opApply qué admite el uso de índices con foreach, pero no es un rango, y no funciona con las funciones basados ​​en la esfera.

+0

¡Gracias, Jonathan! Sé que los rangos y las matrices son tipos diferentes, pero pensé que D podría implementar algún tipo de conversión implícita, ya que los rangos son convertibles en matrices siempre que sean finitas y sus elementos sean de tipo compatible con los de la matriz. Soy consciente de la diferencia en las asignaciones de stack y heap, y sobrecarga computacional y de memoria de array-izing, pero gracias por la advertencia de todos modos :) Además, gracias por dejarlo en claro con IFTI: si entendí esto bien, en el futuro esto podría cambiar para permitir el corte implícito de arreglos estáticos, pero ahora deberíamos usarlo de esta manera debido a la imperfección. – toriningen

+0

IFTI _might_ se cambia para convertir implícitamente matrices estáticas a dinámicas, pero lo dudo. Todavía es necesario que las funciones con plantillas tengan matrices estáticas (por lo que convertirlas para la creación de instancias de plantillas sería malo), e IFTI no lo intenta hasta que encuentre una conversión implícita que funcione (eso sería costoso y cambiaría el semántica de una serie de plantillas). Por lo tanto, espero que siempre tenga que dividir las matrices estáticas para pasarlas a las funciones basadas en el rango, pero se puede hacer una mejora en algún momento para al menos reducir el problema. –

Cuestiones relacionadas