1

Question I have is can you, in one function, pull out one field name of a structure in MATLAB. At the moment I am doing it like this

sb = 3;
TestData.Name1 = [1 2 3];
TestData.Name2 = [4 5 6];
TestData.Name3 = [7 8 9];
TestData.Name4 = [10 11 12];
condition = fieldnames(TestData);
condition = condition{sb}

So condition would come out as being

condition = 

    Name3

I want to know if it can be done more in a way like this

condition = fieldnames(TestData{sb});

Not an essential problem to fix but would be nice to make the code a little more elegant

  • What's `obj.Model.TestData2` ? – Paolo Jan 26 '21 at 15:09
  • It is a 1x1 struct containing 8 37295x1 double arrays, all i want to be able to do is pull out the name of one array without needing to do it in two lines – Tristan Thompson Jan 26 '21 at 15:11
  • Please post a minimal example defining all variables so we can run your code. Let me know when you do so I can remove my downvote – Luis Mendo Jan 26 '21 at 15:22
  • My apologies, i have provided a simplified example here TestData.Name1 = [1 2 3]; TestData.Name2 = [4 5 6]; TestData.Name3 = [7 8 9]; TestData.Name4 = [10 11 12]; sb = 3; condition = fieldnames(TestData) condition = condition{sb} – Tristan Thompson Jan 26 '21 at 15:29
  • `fieldnames` returns a cell array, so it's irrelevant what `obj.Model.TestData2` actually is. The question is asking how to call a function that returns a cell array and index into that cell array in one line. – nekomatic Jan 26 '21 at 15:32
  • @TristanThompson Sorry, I don't see how the code in your comment relates to the variables in your question. Please edit the question code directly, and clearly indicate the result you want to obtain – Luis Mendo Jan 26 '21 at 15:36
  • I've modified the code above, apologies for not being clearer – Tristan Thompson Jan 26 '21 at 15:43
  • 1
    I now see what you want to do. I can't think of any simple way to index directly as you want. You could use `subsref` as [here](https://stackoverflow.com/a/3628885/2586922), but is is a big mess. Also, are you aware that the order of fields is creation order, and so it may be unrealiable? I mean, try for example `test1.a = 10; test1.b = 20; test2.b = 20; test2.a = 10; fieldnames(test1), fieldnames(test2)` – Luis Mendo Jan 26 '21 at 15:49
  • Yes that does look quite messy, i am aware that the field order is in creation order, thats not a big problem for what i'm working on though, either way its not a huge need to fix, just something i thought might be simpler to implement, thanks for the help! – Tristan Thompson Jan 26 '21 at 15:58
  • @TristanThompson I agree with you, it would be nice to have something neater to chain indexing operations in general – Luis Mendo Jan 26 '21 at 23:40

1 Answers1

1

If you don't mind defining a helper function somewhere in your code - which you can do as a one-line anonymous function assignment - then you can do it like this:

curly = @(cellArray, index) cellArray{index};

or

function item = curly(cellArray, index)
    item = cellArray{index};
end

then

>> curly({'foo', 'bar', 'bas'}, 2)
ans =
    'bar'

>> curly(fieldnames(TestData), sb)
ans =
    'Name3'

This is implemented in the Functional Programming Constructs package on MATLAB File Exchange - if you install that package from the Add-on Explorer, you can use the functions it provides without needing to define them yourself, but you then need to remember your code has that dependency if you share your code with others.

Just for completeness, the utterly horrible one-line method without any external dependencies is

subsref(fieldnames(TestData), struct('type', '{}', 'subs', {{sb}}))
nekomatic
  • 5,988
  • 1
  • 20
  • 27
  • Given the need for the code i'm using to be shared with other users that might not be the best solution, but i'll have a look into it – Tristan Thompson Jan 26 '21 at 15:47
  • If you don't want the dependency but you want to use the syntax more than once in one file, you can define it as a local or nested function (or a private class method). It's up to you whether it's better to use the awkward but standard multi-line syntax or have the person who's reading your code need to check what `curly` does. (I called it `curly` because that's what the file exchange package calls it, but you could call it `selectItemFromCellArray` if you wanted to be crystal clear.) – nekomatic Jan 26 '21 at 15:55
  • I honestly think that `condition = fieldnames(TestData); condition = condition{sb};` is a better one-liner than either of the two you posted. :) Still nice proposal. +1 – Cris Luengo Jan 26 '21 at 16:55
  • Also, look at `substruct`, it makes the `subsref` call a lot simpler. – Cris Luengo Jan 26 '21 at 17:06