MATLAB - concatenating items within a cell array - matlab

I have a cell array:
X =
{1x2} {1x2}
X{1} = '' A
X{1 2} = 10 113
I wish to concatenate the sub cells in such a way that
Y = 10 113A
Thanks,
S :-)

y = cellfun(#(a, b) sprintf('%d%s', b, a), x{1}, x{2}, 'UniformOutput', false);

Assuming you have this cell array for X:
X = {{'' 'A'} {10 113}};
You can create your array Y using INT2STR and STRCAT:
Y = strcat(int2str([X{2}{:}].'),X{1}.').';

The Matlab File Exchange has a function written to do precisely this. uniqueRowsCA

For those interested, I think I found a solution.
I redefined my cell array as:
X1 =
{1x2}
X1 = '' 'A'
X2 =
[1x2 double]
X2 = 10 113
I then applied this for loop:
NUM = [];
for i = 1:size(X2') #take the transpose of X2
p = num2str(X2(i)); #convert doubles to strings
str = STRCAT(p, X1(i)); #concatenate
NUM = [NUM str]; #add to another array
end
NUM = '10' '113A'
I am sure there is a more efficient way but MATLAB and I will probably never be on good terms. Sometimes quick and dirty is sufficient!
Cheers,
S :-)

Related

Assign multiple variables at once in MATLAB [duplicate]

Here's an example of what I'm looking for:
>> foo = [88, 12];
>> [x, y] = foo;
I'd expect something like this afterwards:
>> x
x =
88
>> y
y =
12
But instead I get errors like:
??? Too many output arguments.
I thought deal() might do it, but it seems to only work on cells.
>> [x, y] = deal(foo{:});
??? Cell contents reference from a non-cell array object.
How do I solve my problem? Must I constantly index by 1 and 2 if I want to deal with them separately?
You don't need deal at all (edit: for Matlab 7.0 or later) and, for your example, you don't need mat2cell; you can use num2cell with no other arguments::
foo = [88, 12];
fooCell = num2cell(foo);
[x y]=fooCell{:}
x =
88
y =
12
If you want to use deal for some other reason, you can:
foo = [88, 12];
fooCell = num2cell(foo);
[x y]=deal(fooCell{:})
x =
88
y =
12
Note that deal accepts a "list" as argument, not a cell array. So the following works as expected:
> [x,y] = deal(88,12)
x = 88
y = 12
The syntax c{:} transforms a cell array in a list, and a list is a comma separated values, like in function arguments. Meaning that you can use the c{:} syntax as argument to other functions than deal. To see that, try the following:
> z = plus(1,2)
z = 3
> c = {1,2};
> z = plus(c{:});
z = 3
To use the num2cell solution in one line, define a helper function list:
function varargout = list(x)
% return matrix elements as separate output arguments
% example: [a1,a2,a3,a4] = list(1:4)
varargout = num2cell(x);
end
What mtrw said. Basically, you want to use deal with a cell array (though deal(88,12) works as well).
Assuming you start with an array foo that is n-by-2, and you want to assign the first column to x and the second to y, you do the following:
foo = [88,12;89,13;90,14];
%# divide the columns of foo into separate cells, i.e. do mat2cell(foo,3,[1,1])
fooCell = mat2cell(foo,size(foo,1),ones(size(foo,2),1));
[x,y] = deal(fooCell{:});
DEAL is really useful, and really confusing. foo needs to be a cell array itself, I believe. The following seems to work in Octave, if I remember correctly it will work in MATLAB as well:
> foo = {88, 12}
foo =
{
[1,1] = 88
[1,2] = 12
}
> [x,y] = deal(foo{:})
x = 88
y = 12
I cannot comment other answers, so separate addition.
you can use deal(88,12) if you are starting from scalars
deal can be used as a one-liner for non-scalars as well, of course if you already have them in separate variables, say:
a = 123;
b = rand(3);
c = {a, b};
d = struct('field','val')
and now you deal them with one line:
>> [x,y,z,w] = deal(a,b,c,d)
x =
123
y =
0.6370 0.2165 0.6711
0.2945 0.8803 0.2705
0.7633 0.1537 0.0767
z =
[123] [3x3 double]
w =
field: 'val'
However, if they are packed in one variable, you can only deal them if they are in a cell or structure array - with deal(X{:}) for cell array and deal(S.field) for structure array. (In the latter case only one field is dealt, but from all structures in array.) With Matlab v.7+ you can use X{:} and S.field without deal, as noted in other answers.
Create a function arr2vars for convenience
function varargout = arr2vars(arr)
% Distribute elements over variables
N = numel(arr);
if nargout ~= N
error('Number of outputs does not match number of elements')
end
for k = 1:N
varargout{k} = arr(k);
end
You can use it then like this
[~,roi] = imcrop(im);
[x,w,y,h] = arr2vars(roi);
You might be looking for
>>> foo = [88, 12];
>>> [x, y] = deal(foo(1), foo(2))
resulting in
x =
88
y =
12
So you have a working one-liner.
There is an easier way.
x = foo (1, 1)
y = foo (1, 2)
Provides
>> x
x =
88
>> y
y =
12
Full documentation at Mathworks.

Repeat letters within a string in Matlab

I would like to generate a string in Matlab that looks like
"BBBBBBBBBBBBBBBBCCCCCCCCCCCCCC"
where "B" is repeated m times and "C" is repeated n times. Is there any function with inputs similar to ("B","C",n,m) doing this?
You can use the function repelem to repeat the characters the wanted number of times.
str = 'BC' %This is character vector, NOT a string
n = 4; m = 3;
res = repelem(str,[n,m])
res =
'BBBBCCC'
repmat function works on char arrays, and concatenation operators too.
So:
copyfcn = #(B,C,n,m) [repmat(B,[1 n]) repmat(C,[1,m])];
copyfcn('B','C',8,4)
ans =
'BBBBBBBCCCC'
If you want the output to be a string rather than a char array, you can just wrap it in the string() function.
copyfcn2 = #(B,C,n,m) string([repmat(B,[1 n]) repmat(C,[1,m])]);
copyfcn2('B','C',8,4)
ans =
"BBBBBBBBCCCC"
You can make your own function using repmat:
>> f = #(a,b,n,m) [repmat(a, [1 m]) repmat(b, [1 m])];
>> f('B','C',12,14)
ans =
'BBBBBBBBBBBBBBCCCCCCCCCCCCCC'

Push array onto 2D array (matrix) in MATLAB

For God only knows what reason, we're being asked to use MATLAB in an AI course. All I want to do is initialize an array, and push arrays onto it. In Ruby, this would be:
multi_arr = []
an_arr = [1, 2, 3, 4]
multi_arr << an_arr
Done! Unfortunately I can't find a similarly simple solution in MATLAB.
Any advice would be extremely appreciated.
EDIT: for the interested, here's the rather ungraceful solution I arrived at:
child_states = []
child_state = [0,1,2,3,4,5,6,7,8]
% returns [rows, columns]
dimensions = size(child_states)
child_states(dimensions(1)+1, 1:9) = child_state
You can append array to an array in matlab without knowing the dimensions but it won't be very efficient because matlab will allocate space for the whole array each time you do it. Here's how to do it:
arrays = [];
arr1 = [1,2];
arr2 = [3,4,5];
% append first array
arrays = [arrays ,arr1 ]
% append second array
arrays = [arrays ,arr2 ]
arrays =
1 2
arrays =
1 2 3 4 5
if each of the arrays you want to append have the same length, then you can append them as rows:
arrays = [];
arr1 = [1,2,4];
arr2 = [5,6,7];
% append first array
arrays = [arrays ; arr1 ]
% append second array
arrays = [arrays ; arr2 ]
arrays =
1 2 4
arrays =
1 2 4
5 6 7
for more of a ruby like array appending you should use cell arrays:
cells = {};
cells = [cells ,[4,5] ]
cells = [cells ,[1,1,1] ]
cells = [cells ,['hello']]
cells =
[1x2 double] [1x3 double] 'hello'
GIYF. It seems that you are looking for horzcat and vertcat. Check out MATLAB's doc at Creating and concatenating matrices.; from vertcat page:
C = vertcat(A1,...,AN) vertically concatenates arrays A1,...,AN. All arrays in the argument list must have the same number of columns.
If the inputs are multidimensional arrays, vertcat concatenates N-dimensional arrays along the first dimension. The remaining dimensions must match.
Here's a function that's supposed to do what you want: concatenate a row vector to an array regardless of size. This function will check the dimension along the second axis of input and output array and pad zero to whichever one that is smaller so they can be concatenated along the first axis.
function m = freevertcat(m, n)
if isempty(m)
m = cat(1, m, n);
else
size_m = size(m, 2);
size_n = size(n, 2);
if size_m > size_n
n(size_n+1 : size_n + size_m - size_n) = 0
elseif size_n > size_m
m(:, size_m+1 : size_m + size_n - size_m) = 0;
end
m = cat(1, m, n);
end
example usage
m = []
n = [1,2,3,4,5]
m = freevertcat(m,n)
p = [3,3,3]
m = freevertcat(m,p)
You'll get
m = 1 2 3 4 5
3 3 3 0 0

Matlab How to perform substraction for multiple cell arrays?

The code below is only for 2 cell arrays, named B and C
A=cellfun(#minus, B, C, 'UniformOutput', false)
I want to perform a loop to be able to perform substraction for all my cell arrays.
Example of B{i} and C{i} are below:
B{1}=[0.435]
B{2}=[0.333] [0.532]
B{3}=[0.021] [0.432] [0.312] //command window output
C{1}=[0.211]
C{2}=[0.243] [0.116]
C{3}=[0.553] [0.212] [0.375] //command window output
B{1}-C{1}
B{2}-C{2}
B{3}-C{3}
I tried to include {i} behind A , B and C to become something like:
A{i}=cellfun(#minus, B{i}, C{i}, 'UniformOutput' , false)
However, it seems like it's not working. Is there any solution for this? Thanks
EDIT:
You have unnecessary nested cell-arrays, i.e B is a cell-array of cell-arrays, and B{i} is a cell-array of numbers.
If you want to keep that format, here is one way to compute the result using cellfun (A will also be a cell-array of cell-arrays of numbers):
% exiting data
B = cell(3,1);
B{1} = {0.435};
B{2} = {0.333, 0.532};
B{3} = {0.021, 0.432, 0.312};
C = cell(3,1);
C{1} = {0.211};
C{2} = {0.243, 0.116};
C{3} = {0.553, 0.212, 0.375};
A = cellfun(#(b,c)cellfun(#minus, b, c, 'Uniform',false), B, C, 'Uniform',false);
Otherwise I suggest you cut down on the level of nesting, and use this instead:
% note the difference between square-brackets and curly-brackets
B = cell(3,1);
B{1} = [0.435];
B{2} = [0.333, 0.532];
B{3} = [0.021, 0.432, 0.312];
C = cell(3,1);
C{1} = [0.211];
C{2} = [0.243, 0.116];
C{3} = [0.553, 0.212, 0.375];
Now you can compute the result using a single cellfun (no nesting):
A = cellfun(#minus, B, C, 'Uniform',false)

How can I convert a vector to a cell array?

I have a column vector I want to convert to a cell array such as:
A = rand(10,1);
B = cell(10,1);
for i=1:10
B{i} = A(i);
end
B =
[0.6221]
[0.3510]
[0.5132]
[0.4018]
[0.0760]
[0.2399]
[0.1233]
[0.1839]
[0.2400]
[0.4173]
How can I do this without an explicit for loop?
I tried:
B{:} = A(:)
and
[B{:}] = deal(A)
with no luck...
Also if possible, how can I do the same thing for a matrix, i.e. have each element in a cell by itself?
Use the function num2cell:
B = num2cell(A);
Works with matrices too.