2009-12-10 8 views
32

Tengo una estructura con muchos campos que son vectores de diferentes longitudes. Me gustaría acceder a los campos dentro de un ciclo, en orden. Intenté getfield de la siguiente manera, pero a MATLAB no le gusta eso. ¿Cómo puedo hacer esto?¿Cómo accedo a los campos de la estructura de forma dinámica?

S = struct('A', [1 2], 'B',[3 4 5]); 
SNames = fieldnames(S); 
for loopIndex = 1:2 
    field = getfield(S, SNames(loopIndex)); 
    %do stuff w/ field 
end 
??? Index exceeds matrix dimensions 

Estoy usando estructuras en primer lugar porque una matriz tendría problemas con las diferentes longitudes de campo. ¿Hay una mejor alternativa a eso?

Respuesta

42

Pruebe la referencia de campo dinámico donde pone una cadena entre paréntesis como se ve en la línea que define cosas.

S = struct('A', [1 2], 'B',[3 4 5]); 
SNames = fieldnames(S); 
for loopIndex = 1:numel(SNames) 
    stuff = S.(SNames{loopIndex}) 
end 

Estoy de acuerdo con Steve and Adam. Usa celdas ¡Esta sintaxis es adecuada para personas en otras situaciones!

5

El enfoque de getfield está bien (aunque no tengo MATLAB disponible en este momento y no está claro para mí por qué lo anterior no funcionaría).

Para una estructura de datos alternativa, es posible que también desee examinar las matrices de MATLAB. También le permiten almacenar e indexar vectores de longitud variable.

+1

Dada su descripción de por qué está utilizando una estructura, estoy de acuerdo con Adam. Debería considerar usar una matriz de celdas. –

16

Hay tres puntos que me gustaría hacer aquí:

  • La razón de que está recibiendo un error en el código anterior es debido a la forma en que está indexando SNames. La función fieldnames devuelve cell array de cadenas, por lo que debe usar content indexing (es decir, llaves) para acceder a los valores de cadena. Si cambia la cuarta línea de su código a este:

    field = getfield(S, SNames{loopIndex}); 
    

    , entonces su código debería funcionar sin error.

  • Como sugiere MatlabDoug, puede utilizar dynamic field names para evitar tener que utilizar getfield (que produce código más limpio que mira, en mi opinión).

  • El suggestion from Adam para usar un cell array en lugar de una estructura está justo en la marca. En general, esta es la mejor manera de recopilar una serie de matrices de diferente longitud en una sola variable. Su código podría terminar buscando algo como esto:

    S = {[1 2], [3 4 5]};  % Create the cell array 
    for loopIndex = 1:numel(S) % Loop over the number of cells 
        array = S{loopIndex};  % Access the contents of each cell 
        % Do stuff with array 
    end 
    
+0

Usar una matriz de celdas en lugar de una estructura es menos detallado. – Wok

3

Puede utilizar la notación de dos puntos para evitar índices:

S = struct('A', [1 2], 'B',[3 4 5]); 
SNames = fieldnames(S); 
for SName = [SNames{:}] 
    stuff = S.(SName) 
end 
2

Si es necesario utilizar una estructura de lo que he encontrado funcionó muy bien era para convertirte primero a una célula, entonces tienes lo mejor de ambos mundos.

S = struct('A', [1 2], 'B',[3 4 5]); 
S_Cell = struct2cell(S); 
%Then as per gnovice 
for loopIndex = 1:numel(S_Sell) % Loop over the number of cells 
    array = S{loopIndex};   % Access the contents of each cell 
    %# Do stuff with array 
end 

he usado algo similar para algo que se generó en una estructura y luego que necesitaba para acceder a ella como una matriz, en ese caso era tan simple como

M = cell2mat(struct2cell(S)); 

para convertirlo en una matriz

+0

M = table2array (struct2table (S)); – BigChief

0

Solo para agregar otra respuesta a la mezcla. Me gusta la solución de @Niver pero solo funciona para campos con nombres de una sola letra. La solución que utilicé fue:

S = struct('A', [1 2], 'B',[3 4 5], 'Cee', [6 7]); 
for SName = fieldnames(S)' 
    stuff = S.(SName{1}) 
end 

for se iterar a través de las columnas de una matriz de células (por lo tanto la transpuesta en fieldnames(S)' Para cada bucle SName se convierte en una serie de células de 1x1 así que usamos la indización de contenido para acceder a la primera y única. elemento con SName{1}.

Cuestiones relacionadas