MATLAB Answers

Evan
0

Generate comma separated list in single line of code?

Asked by Evan
on 13 Jun 2017
Latest activity Edited by Adam
on 13 Jun 2017
I would like to put a piece of code within an expression which generates a comma separated list, without having to create a dummy variable. Is this possible? I was trying to use subsref(), like this:
subsref(repmat({'A'},1,4),struct('type','{}','subs',{{':'}}))
But this only returns a single output. It seems like subsref can't actually behave like A{:} . Is there another way?
The specific reason I would like to do this is for indexing an array where the dimension is unknown prior to runtime. So instead of (for example)
idx = [{1} repmat({':'},1,ndims(inputData)-1)];
output = A(idx{:});
I could do something like
output = A(<expression>);

  8 Comments

That's fine. I just thought it might be confuse people.
Don't worry about others. They will cope just fine :)
This is a relatively uncommon topic to deal with, so regarding this thread:
  1. beginners are unlikely to stumble across it.
  2. it documents particular concepts that otherwise do not get discussed much.
It matters more whether there is a clear and useful answer than whether the initial question might confuse. If it were a question where the answers just add to the confusion then it would be bad, but if the accepted answer (accepting Stephen's answer would be useful!) clears up the confusion then that is fine.
Hence, I removed the flag from the question.

Sign in to comment.

Tags

Products

3 Answers

Answer by Stephen Cobeldick on 13 Jun 2017
Edited by Stephen Cobeldick on 13 Jun 2017
 Accepted Answer

"I would like to put a piece of code within an expression which generates a comma separated list, without having to create a dummy variable. Is this possible?"
No.
Read this answer and the comments below for the reasons why.
"But this only returns a single output."
No, actually your code works perfectly and returns all of the elements of the cell array, just as we would expect. You just didn't define output variables for all of the outputs of the function:
>> Z = {'A','B','C','D'};
>> [a,b,c,d] = subsref(Z,struct('type','{}','subs',{{':'}}))
a =
A
b =
B
c =
C
d =
D
Because subsref is a perfectly normal function its outputs are only allocated to multiple output variables when those variables are defined in a comma-separated list as output arguments. Exactly like any other function, we would not expect
max(X)
to return both of its output arguments until we have defined both of them in a comma-separated list:
[val,idx] = max(X)
Exactly the same applies to subsref, because it is a normal function as well, and is consistent with what the documentation states regarding returning multiple function outputs:
This all begs the question: what is {:} if not a function? Answer: I have no idea.
Summary: your question is basically the wrong way around. You asked about why subsref behaves strangely, whereas in fact subsref behaves perfectly normally for a MATLAB function. It is actually {:} that behaves strangely: you should be asking about that!

  3 Comments

I didn't mean to convey that subsref() was behaving strangely.
Everything you've written about function outputs makes sense to me. I tried subsref() because of this example in the documentation :
The syntax
A{1:2}
calls
B = subsref(A,S)
where
S.type='{}'
and
S.subs={[1 2]}
Perhaps what it should say is that it A{:} calls
[B, C] = subsref(A,S)
In any case, my question is not "why isn't subsref working correctly," but rather "how to get a comma separated list on a single line?". So maybe your answer would have made more sense as a comment (respectfully).
I'll also add that subsref does not "see" multiple outputs if I place it inside an indexing expression where multiple outputs would be appropriate, e.g.
B(subsref(A,S))
Where B is a multidimensional array. Not that this is how I think it should behave, but I don't know why this couldn't have been implemented.
"but I don't know why this couldn't have been implemented."
Because, for the reasons that I gave in my answer, how many outputs a MATLAB function returns is demand driven, i.e. determined by how many output arguments have been specified, and is not driven by how many outputs the function potentially has. This also gives predictable results, for example max can accept two inputs and two outputs, yet because the output is demand driven this
max(max(X))
means the the inner max simply provides one output to the outer max, exactly as we would want (and sometimes use with a matrix). What you are suggesting is that the inner max should force the outer max to accept both of its outputs, giving a mathematically unusual maximum of some indices and some values of X. What you want to do would force MATLAB to make the above equivalent to:
[val,idx] = max(X)
max(val,idx)
Lets have a look at another simple example, finding the highest index of non-zeros in a vector:
>> X = [9,0,5];
>> max(find(X))
ans = 3
But note that find can have one, two, or three outputs (and these outputs also change depending on how many there are... but that is another layer of complexity). Following your suggestion all three of them should be provided to max, which would then be an error. How would that be useful? Even with just two of them would be equivalent to:
>> X = [9,0,5];
>> [R,C] = find(X);
>> max(R,C)
ans =
1 3
I do not see how this would be an improvement on MATLAB. It makes little sense (respectfully).
"but I don't know why this couldn't have been implemented."
Now I do. Thanks! BTW, no sarcasm intended in the earlier comment.

Sign in to comment.


Answer by Wonsang You on 13 Jun 2017

Please try the following command.
subsref(repmat({'A'},1,4),struct('type','()','subs',{{':'}}))

  1 Comment

This answer is irrelevant to the topic at hand: it does not return a comma-separated list as the original question asks about, and even the title clearly states: "Generate comma separated list.."
This code simply returns a cell array, and is equivalent to (:).
The original question asks about generating a comma-separated list, equivalent to {:}.
Someone apparently does not know the difference, and voted for it. Perhaps they liked the pretty output.

Sign in to comment.


Answer by Walter Roberson
on 13 Jun 2017

Expand = @(cell) cell{:};
Expand(repmat({'A'},1,4))

  0 Comments

Sign in to comment.