Employing conditions in cellfun MATLAB - matlab

The questions is:
A=[9 10];
And I want to obtain B={'09','10'};
I made this:
for hij=1:size(A,1)
if A{hij}<9
B{hij}=strcat('0',num2str(A{hij}),'');
else
B{hij}=strcat('',num2str(A{hij}),'');
end
end
But I was wondering if there is any posibility to make that without using a loop, maybe using a "cellfun"; thanks!

Is this what you want?
>> B = num2str(A(:),'%02d'); %// second argument to num2str is format spec
B =
09
10
This gives a string matrix B. To convert B into a cell array of strings:
>> B = mat2cell(B,ones(1,size(B,1))).';
B =
'09' '10'
or, as noted by Divakar,
>> B = cellstr(B).';
B =
'09' '10'

Luis answer is good. Just for completeness, you can use arrayfun if you really want:
C = arrayfun(#num2str, A,'UniformOutput', 0 );

Related

Matrix generation from a vector

I have a column vector A. When A is a scalar I can use the colon operator to generate a vector like so
B = A-m:n:A+p
However, what I want to do is different. I want the result B to look like so,
[A-m, A-m+1 ... A ... , A+n-1, A+n]
I know I can accomplish this by using repmat on -m:n:p followed with a bsxfun added with the original A matrix.
Is there a more direct method?
If you just want to copy a handful instances of column vector v, you can always use
B = [v, v, v, ... v];
Or for row vector
B = [v ; v ; v ; ... v];
One easy vectorized way is this:
NewMatrix = diag(A)*ones(length(A),m+n+1) + ones(length(A),m+n+1)*diag(-m:1:n)
not a one-liner...
>> a=[1;2];
>> r=3:2:10;
>> repmat(a,1,size(r,2))+repmat(r,size(a,1),1)
ans =
4 6 8 10
5 7 9 11

Combining letter vector with number vector matlab

I wish to combine a vector of letters
AssetList(1,2:end)
ans =
'a' 'b' 'c' 'd' 'e'
with a vector of numbers
x
x =
0.3857
0.2143
0.0000
0
0.4000
to create a table where a=0.3857 etc but I get errors no matter what I try. For example:
y=cat(2,alldata(1,2:end)',x)
Error using cat
Dimensions of matrices being concatenated
are not consistent.
I am not sure what you want, perhaps something like this:
x = 'a':'e'
y = 11:15
C = cell(5,2)
for t = 1:5
C{t,1}=x(t)
C{t,2}=y(t)
end
It can of course be vectorized, but I find this solution easier to understand.
Standard MATLAB arrays are only able to cope with one data type, e.g. either chars or doubles. If you want to combine multiple types of data, you will need to employ structs or cells, as Dennis Jaheruddin has done in his answer.
See attached an example on how to put this into an array of structs:
for n=1:5
y(n).character = AssetList(1,n+1)
y(n).number = x(n)
end
Your approach almost works. You only need to transform x into a cell array (with mat2cell) before using cat:
y = cat(2, alldata(1,2:end).', mat2cell(x, ones(1,numel(x))));

How can I combine numbers in a row into a single number

A = [7,2,3,4,4]
I want to combine them to:
B = 72344
I am new to matlab. Is there any build in function that can do that?
Thanks in advance.
Here is a solution
>> A = [7,2,3,4,4];
>> B=A*(10.^(length(A)-1:-1:0))'
B = 72344
Note #BenVoigt's comment:
>> A = [7,2,3,4,4;2,3,4,5,3]
A =
7 2 3 4 4
2 3 4 5 3
>> B=A*(10.^(length(A)-1:-1:0))'
B =
72344
23453
zz = str2num(num2str(A(:))')
zz =
72344
is straightforward
You could also simply add '0' as a shift into the range of numeric characters: A+'0'. Then, B = str2double(char(A+'0')).
You can apply num2str and strrep as follows:
>> A = [7,2,3,4,4];
>> B = str2num(strrep(num2str(A(:)'),' ',''))
B =
72344
Note that A(:)' is used to ensure a row vector. However, webpat's answer is more concise since you can leave off the ' and strrep is not required. Also, the mathematical solution by damienfrancois seem more elegant than using strings.

Vectorization of multi-level indexing of structs in MATLAB

Say I have the following in MATLAB:
a(1).b.c = 4;
a(2).b.c = 5;
a(3).b.c = 7;
....
I would like to collect the values [4 5 7 ...] in a single array, without looping and in a vectorized manner.
I have tried:
>> a(:).b.c
# Error: Scalar index required for this type of multi-level indexing.
and
>> a.b.c
# Error: Dot name reference on non-scalar structure.
but they didn't work. The best I could come up with was:
arrayfun(#(x) x.b.c, a);
but as far as I understand arrayfun is not vectorized, or is it?
Your call to arrayfun seems idiomatic enough to me in Matlab. I don't think this is vectorized but it's well optimized and maybe the fastest way.
You should also try to benchmark with a loop to see if the JIT compiler performs well here. It's hard to know without testing.
You can do it in two lines:
>> s = [a.b];
>> y = [s.c]
y =
4 5 7
Another possible one-liner (less readable!):
>> y = squeeze(cell2mat( struct2cell([a.b]) ))
y =
4
5
7
a.b returns multiple outputs, so you can't expect to call a function on it. The best one-liner I can think of without using arrayfun is:
y = subsref([a.b], substruct('.', c));
Note that a.b.c is effectively the same as:
y = subsref(a.b, substruct('.', c))
Which is why it shouldn't work for non-scalar a.

MATLAB: comparison of cell arrays of string

I have two cell arrays of strings, and I want to check if they contain the same strings (they do not have to be in the same order, nor do we know if they are of the same lengths).
For example:
a = {'2' '4' '1' '3'};
b = {'1' '2' '4' '3'};
or
a = {'2' '4' '1' '3' '5'};
b = {'1' '2' '4' '3'};
First I thought of strcmp but it would require looping over one cell contents and compare against the other. I also considered ismember by using something like:
ismember(a,b) & ismember(b,a)
but then we don't know in advance that they are of the same length (obvious case of unequal). So how would you perform this comparison in the most efficient way without writing too many cases of if/else.
You could use the function SETXOR, which will return the values that are not in the intersection of the two cell arrays. If it returns an empty array, then the two cell arrays contain the same values:
arraysAreEqual = isempty(setxor(a,b));
EDIT: Some performance measures...
Since you were curious about performance measures, I thought I'd test the speed of my solution against the two solutions listed by Amro (which use ISMEMBER and STRCMP/CELLFUN). I first created two large cell arrays:
a = cellstr(num2str((1:10000).')); %'# A cell array with 10,000 strings
b = cellstr(num2str((1:10001).')); %'# A cell array with 10,001 strings
Next, I ran each solution 100 times over to get a mean execution time. Then, I swapped a and b and reran it. Here are the results:
Method | Time | a and b swapped
---------------+---------------+------------------
Using SETXOR | 0.0549 sec | 0.0578 sec
Using ISMEMBER | 0.0856 sec | 0.0426 sec
Using STRCMP | too long to bother ;)
Notice that the SETXOR solution has consistently fast timing. The ISMEMBER solution will actually run slightly faster if a has elements that are not in b. This is due to the short-circuit && which skips the second half of the calculation (because we already know a and b do not contain the same values). However, if all of the values in a are also in b, the ISMEMBER solution is significantly slower.
You can still use ISMEMBER function like you did with a small modification:
arraysAreEqual = all(ismember(a,b)) && all(ismember(b,a))
Also, you can write the loop version with STRCMP as one line:
arraysAreEqual = all( cellfun(#(s)any(strcmp(s,b)), a) )
EDIT: I'm adding a third solution adapted from another SO question:
g = grp2idx([a;b]);
v = all( unique(g(1:numel(a))) == unique(g(numel(a)+1:end)) );
In the same spirit, Im performed the time comparison (using the TIMEIT function):
function perfTests()
a = cellstr( num2str((1:10000)') ); %#' fix SO highlighting
b = a( randperm(length(a)) );
timeit( #() func1(a,b) )
timeit( #() func2(a,b) )
timeit( #() func3(a,b) )
timeit( #() func4(a,b) )
end
function v = func1(a,b)
v = isempty(setxor(a,b)); %# #gnovice answer
end
function v = func2(a,b)
v = all(ismember(a,b)) && all(ismember(b,a));
end
function v = func3(a,b)
v = all( cellfun(#(s)any(strcmp(s,b)), a) );
end
function v = func4(a,b)
g = grp2idx([a;b]);
v = all( unique(g(1:numel(a))) == unique(g(numel(a)+1:end)) );
end
and the results in the same order of functions (lower is better):
ans =
0.032527
ans =
0.055853
ans =
8.6431
ans =
0.022362
Take a look at the function intersect
What MATLAB Help says:
[c, ia, ib] = intersect(a, b) also
returns column index vectors ia and ib
such that c = a(ia) and b(ib) (or c =
a(ia,:) and b(ib,:)).