Conditionally Flip Sign in Table

I have a very simple question. Based on a matrix like this one:
A = [repmat({'Yes'},3,1) , repmat({'2'},3,1); repmat({'No'},3,1) , repmat({'2'},3,1)];
I want to flip the sign of column 2 if the entry in colum one is 'No', but leave it as is if the entry in colun one is 'Yes'.
The result should be the following:
B = [repmat({'Yes'},3,1) , repmat({'2'},3,1); repmat({'No'},3,1) , repmat({'-2'},3,1)];
I suppose I can do this using one line of code using cellfun, but I am not sure what is the most optimized way.
Thx for your help!

 Risposta accettata

Matt Tearle
Matt Tearle il 4 Nov 2014
Modificato: Matt Tearle il 4 Nov 2014
One liner:
A(strcmp(A(:,1),'No'),2) = strcat('-',A(strcmp(A(:,1),'No'),2))
Slightly cleaner with two lines:
idx = strcmp(A(:,1),'No');
A(idx,2) = strcat('-',A(idx,2))
But... if you're worrying about efficiency, I'd want to know if A has to be in the form it is. Does the second column have to text, rather than numeric?
And do you have 13b or later (or Statistics TB)? Because I think you might have an easier time using tables and categoricals. For example:
% Make a table version of A
Atable = cell2table(A,'VariableNames',{'YesOrNo','Number'})
% Convert strings to categories and string numbers to actual numbers
Atable.YesOrNo = categorical(Atable.YesOrNo)
Atable.Number = str2double(Atable.Number)
% Now, do the sign flipping
Atable.Number(Atable.YesOrNo == 'No') = -Atable.Number(Atable.YesOrNo == 'No')

6 Commenti

Hi, to answer your second question first, no I have 13a.
Now your solution uses the simmetry of my dumb example, but in real life the value on the second colum changes on every line. So your code does not work on this
A = [repmat({'Yes'},4,1) , repmat({'2'},4,1); repmat({'No'},3,1) , repmat({'1'},3,1)];
Imagine the second colum is text containing different numbers.
Thx for ur help!
But wait a sec, a slight modification of your code seems to work:
A(strcmp(A(:,1),'No'),2) = strcat('-',A(strcmp(A(:,1),'No'),2))
I'm not sure what the problem is, or what the difference is between the modification you've posted and what I posted. (I initially had a small typo, but fixed it immediately. Perhaps you somehow saw the old version...?)
Anyway, it's working as needed now?
With 13a you could use dataset arrays and nominals if you have Statistics TB. (They are very similar to what became tables and categoricals in MATLAB in 13b.) But even without going that far, you can also still use a cell array of strings and a corresponding numeric array. That would reduce a lot of unnecessary memory overhead, if the arrays are large.
Hi, yes on the right handside you had a 'Yes' initially. With 'No' it sort of works, but not quite, as in the case of a negative number initially, say '-2', I get '--2' instead of '2'.
I need to convert to a number, multiply by -1 and transform back to cell.
I was thinking of something like this
A(strcmp(A(:,1),'No'),2) = num2cell(cell2mat(A(strcmp(A(:,1),'No'),2)) * -1)
But does not seem to work.
Ah, right, now I see what you mean. If you want to keep them as strings, then you could do:
idx = strcmp(A(:,1),'No');
A(idx,2) = cellstr(num2str(-str2double(A(idx,2))))
But, again, I think you should really think about how you're storing the data, and whether it has to be that way. (I can't answer that without knowing more about your application.) If you could store it as two variables -- a cell array of strings and a numeric vector -- then this would be simpler and more efficient:
% separate out columns
YesOrNo = A(:,1)
numbers = str2double(A(:,2))
% flip signs
idx = strcmp(YesOrNo,'No')
numbers(idx) = -numbers(idx)
This works like a charm. Thx! :)

Accedi per commentare.

Più risposte (0)

Categorie

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!

Translated by