Creating a Cell Array but I've Got The Size Wrong and Its Missing Certain Elements

This section of code is meant to take an even number of input arguments and return them as a cell array with two columns, one for the name and one for the value. With the test input I've been given it is only returning the the third and forth input arguments as a 1x1 cell array where as I'm looking for a 2x2 cell array. Is the issue with the ii indexing? Can I not do it like I've written here?
db = name_value_pairs('name','John Smith','age',32)
function [db]=name_value_pairs(varargin)
for ii = 1:2:(length(varargin)-1)
for i = 1:(length(varargin)/2)
x(i,1) = varargin(ii);
end
end
for ii = 2:2:length(varargin)
for i = 1:(length(varargin)/2)
x(i,2) = varargin(ii);
end
end
db = {x};
end
db =
1×1 cell array
{2×2 cell}
Thank you for any help or advice!

 Réponse acceptée

The logic in your code seems to over-kill for this task. db = {x} statement make the return value a 1x1 array. If you change it to db = x you will get a 2x2 array.
You can use reshape() to write a one-liner
function [db]=name_value_pairs(varargin)
db = reshape(varargin, 2, []).';
end

10 commentaires

Thank you Ameer! So I tried both suggestions and each one improved the output a little but I'm still not there. Changing db ={x} to db = x returend the right sized array but I'm still overwriting data:
db = % using db = x
2×2 cell array
{'age'} {[32]}
{'age'} {[32]}
The reshape function is great however it returns 'name' and 'age' in the first row where as I need tham in the first column. I checked the help documentation for reshape() but I didn't see a method to switch those. Is it possible to transpose a cell array like you can with a matrix?
db = % using reshape()
2×2 cell array
{'name' } {'age'}
{'John Smith'} {[ 32]}
EDIT: So you I've determined you can transpose a cell array, so thanks to you I've solved the main issue! Tangentially related to this, can I use ischar() to verify whether the name column, the first column, contains only character arrays?
I am glad to be of help!
Yes, The logic of for-loop is not correct, and it just makes the code complex. reshape() is a cleaner option.
You can use ischar() like this to see which of the values in first columns are character arrays.
cellfun(@ischar, db(:,1))
Again thank you so much. My only remaining issue is the failure of my if-else statements:
function [db]=name_value_pairs(varargin)
if nargin < 2
db ={};
elseif rem(nargin, 2) ~= 0 % I thought this would check for even # of inputs
db ={};
else
x = reshape(varargin, 2, []);
db = x';
end
if cellfun(@ischar, db(:,1)) ~= 1
db = {};
else
db = db;
end
end
If there are not an even number of inputs then db should be an empty cell array but when I try using:
db = name_value_pairs('name','John Smith','age')
I get an error that the index in position 2 exceeds the array bounds. But when that condition is encountered I was expecting the code to return an empty cell array. I'm a bit miffed at this error since if-else statements are pretty basic and I thought I had a good grasp on them.
The error happens because if you have an odd number of inputs, the first if-block return db={}, but then in the second if-block you are trying to access db(:,1) [first column of db]. Therefore, MATLAB throws an error since there is no first column.
Check the following code
function [db]=name_value_pairs(varargin)
if rem(nargin, 2) ~= 0 % I thought this would check for even # of inputs
db ={};
else
x = reshape(varargin, 2, []);
db = x';
if cellfun(@ischar, db(:,1)) ~= 1
db = {};
end
end
end
if cellfun(@ischar, db(:,1))
ischar returns 1 if true and 0 if false correct? That check isn't working with the input
db = name_value_pairs(13,'John Smith','age', 32)
as it returns a 2x2 cell array with 13 in place of name. In the line above I set db = x' but the nested if statement should return an empty array if ischar is false right?
I finally got the char test condition to work. I thought that cellfun(@ischar, db(:,1)) ~= 1 would check that ALL cell values in the first column are character arrays. It does not and still passes as long as one of them is a char. So my current version of the function is this:
function [db]=name_value_pairs(varargin)
myCell = varargin;
if nargin < 2
db ={};
elseif rem(nargin, 2) ~= 0
db ={};
elseif sum(cellfun(@ischar, myCell(1:3))) ~= 3
db = {};
else
x = reshape(varargin, 2, []);
db= x';
end
end
I've almost passed the assignment but I'm still failing the Random Inputs test. Unfortunately the automatic grader isn't displaying what those inputs are so I can't really work on a solution. I made a post in the class forum so hopefully one of the instructors responds. I suspect that the random inputs are just random strings. The ischar test condition should check for those right?
Stephen23
Stephen23 le 4 Sep 2020
Modifié(e) : Stephen23 le 4 Sep 2020
"The ischar test condition should check for those right?"
Sort of... note that character arrays can have any size, including any number of rows or pages, etc. So ischar returns true for a 2x3 character matrix and for a 5x3x2 character array and even for a 0x0x1 character array. It is possible that the automatically generated tests include such cases, but that they expect the test to only pass for row vectors, i.e. character arrays where ndims==2 and the number of rows==1.
Another problem is that cellfun() will return an array, which can create unexpected results when directly used with if-statement. Using sum(cellfun(@ischar, myCell(1:3))) ~= 3. Which only works when if there are three rows, and myCell(1:3) is also not correct to use here.
Try this code
function [db]=name_value_pairs(varargin)
if rem(nargin, 2) ~= 0 % I thought this would check for even # of inputs
db ={};
else
x = reshape(varargin, 2, []);
db = x';
if all(cellfun(@ischar, db(:,1)))
db = {};
end
end
end
Thank you Stephen and Ameer. Ameer, shouldn't it be:
if all(cellfun(@ischar, db(:,1)))
db = db;
else
db = {};
end
Or something similar? The way you have it written if @ischar is true then db is set as an empty array, right?
EDIT: Ok, finally got it!
function [db]=name_value_pairs(varargin)
if nargin < 2
db ={};
elseif rem(nargin, 2) ~= 0
db ={};
else
x = reshape(varargin, 2, []);
z = x';
if all(cellfun(@ischar, z(:,1)))
db = z;
else
db = {};
end
end
end
Thank you both so much, especially you Ameer. I appreciate the help and your endless patience.
Yes, you are correct. The condition should be reversed. The following is also equivalent.
function [db]=name_value_pairs(varargin)
if rem(nargin, 2) ~= 0 % I thought this would check for even # of inputs
db ={};
else
db = reshape(varargin, 2, []);
if ~all(cellfun(@ischar, db(:,1)))
db = {};
end
end
end

Connectez-vous pour commenter.

Plus de réponses (0)

Catégories

Produits

Community Treasure Hunt

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

Start Hunting!

Translated by