Please help: Cell contents assignment to a non-cell array object.

3 visualizaciones (últimos 30 días)
David Davis
David Davis el 24 de Nov. de 2016
Editada: Stephen23 el 26 de Nov. de 2016

This is the error message/output:

num2word(1234)

nDigits =

     1     2     3     4

Cell contents assignment to a non-cell array object.

Error in num2word (line 178) wordArray{i} = 'Two Hundred';

I originally wrote this for just numbers 1 through 9 and it worked perfectly, it was only after I made it work for up to a million that it stopped working and all I did was basically copy paste my original switch and then add if conditionals.

Here is my code.....

function [wordArray] = num2word(num)
nDigits = dec2base(num,10) - '0'
wordArray = [' ':length(nDigits):' '];
wordArray = cellstr(wordArray);
%wordArray = cell(1,20); tried this but no..
%these variables are switches, one the of statement containing them is ran
%they change values meaning that the switch has been turned off
a = 0;
b = 0;
c = 0;
d = 0;
e = 0;
f = 0;
for i=1:(length(nDigits))
    %millions
    if length(nDigits) >= 7 && i == 1
          switch nDigits(i)
              case 0
                  wordArray{i} = ' ';
              case 1
                  wordArray{i} = 'One Million';
              case 2
                  wordArray{i} = 'Two Million';
              case 3
                  wordArray{i} = 'Three Million';
              case 4
                  wordArray{i} = 'Four Million';
              case 5
                  wordArray{i} = 'Five Million';
              case 6
                  wordArray{i} = 'Six Million';
              case 7
                  wordArray{i} = 'Seven Million';
              case 8
                  wordArray{i} = 'Eight Million';
              case 9
                  wordArray{i} = 'Nine Million';
          end
          %hundred thousands
      elseif length(nDigits) >= 6 && a == 0
          a = 1;
          switch nDigits(i)
              case 0
                  wordArray{i} = ' ';
              case 1
                  wordArray{i} = 'One Hundred and';
              case 2
                  wordArray{i} = 'Two Hundred and';
              case 3
                  wordArray{i} = 'Three Hundred and';
              case 4
                  wordArray{i} = 'Four Hundred and';
              case 5
                  wordArray{i} = 'Five Hundred and';
              case 6
                  wordArray{i} = 'Six Hundred and';
              case 7
                  wordArray{i} = 'Seven Hundred and';
              case 8
                  wordArray{i} = 'Eight Hundred and';
              case 9
                  wordArray{i} = 'Nine Hundred and';
          end
          % Ten thousands
      elseif length(nDigits) >= 5 && b ==0;
          b = 1;
          switch nDigits(i)
              case 0
                  wordArray{i} = ' ';
              case 1
                  % if wordArray{i+1} > 0 (teens); the c variable is so that
                  % we can leave the next cell blank ''
                  switch nDigits(i+1)
                      case 0
                          wordArray{i} = 'Ten Thousand';
                          c = 2;
                      case 1
                          wordArray{i} = 'Eleven Thousand';
                          c = 2;
                      case 2
                          wordArray{i} = 'Twelve Thousand';
                          c = 2;
                      case 3
                          wordArray{i} = 'Thirteen Thousand';
                          c = 2;
                      case 4
                          wordArray{i} = 'Fourteen Thousand';
                          c = 2;
                      case 5
                          wordArray{i} = 'Fifteen Thousand';
                          c = 2;
                      case 6
                          wordArray{i} = 'Sixteen Thousand';
                          c = 2;
                      case 7
                          wordArray{i} = 'Seventeen Thousand';
                          c = 2;
                      case 8
                          wordArray{i} = 'Eighteen Thousand';
                          c = 2;
                      case 9
                          wordArray{i} = 'Nineteen Thousand';
                          c = 2;
                  end
              case 2
                  wordArray{i} = 'Twenty ';
              case 3
                  wordArray{i} = 'Thrirty ';
              case 4
                  wordArray{i} = 'Fourty ';
              case 5
                  wordArray{i} = 'Fivty ';
              case 6
                  wordArray{i} = 'Sixty ';
              case 7
                  wordArray{i} = 'Seventy ';
              case 8
                  wordArray{i} = 'Eighty ';
              case 9
                  wordArray{i} = 'Ninety ';
          end
          % Ten thousands
      elseif length(nDigits) >= 4 && c ==0;
          c = 1;
          switch nDigits(i)
              case 0
                  wordArray{i} = ' ';
              case 1
                  wordArray{i} = 'One';
              case 2
                  wordArray{i} = 'Two Thousand';
              case 3
                  wordArray{i} = 'Three Thousand';
              case 4
                  wordArray{i} = 'Four Thousand';
              case 5
                  wordArray{i} = 'Five Thousand';
              case 6
                  wordArray{i} = 'Six Thousand';
              case 7
                  wordArray{i} = 'Seven Thousand';
              case 8
                  wordArray{i} = 'Eight Thousand';
              case 9
                  wordArray{i} = 'Nine Thousand';
          end
          % Ten thousands for teens
      elseif length(nDigits) >= 4 && c ==2;
          c = 1;
          wordArray{i} = '';
          % Hundreds
      elseif length(nDigits) >= 3 && d ==0;
          d = 1;
          switch nDigits(i)
              case 0
                  wordArray{i} = ' ';
              case 1
                  wordArray{i} = 'One Hundred';
              case 2
                  wordArray{i} = 'Two Hundred';
              case 3
                  wordArray{i} = 'Three Hundred';
              case 4
                  wordArray{i} = 'Four Hundred';
              case 5
                  wordArray{i} = 'Five Hundred';
              case 6
                  wordArray{i} = 'Six Hundred';
              case 7
                  wordArray{i} = 'Seven Hundred';
              case 8
                  wordArray{i} = 'Eight Hundred';
              case 9
                  wordArray{i} = 'Nine Hundred';
          end
      elseif length(nDigits) >= 2 && e ==0;
          e = 1;
          switch nDigits(i)
              case 1
                  % if wordArray{i+1} > 0 (teens); the f variable is so that
                  % we can leave the next cell blank ''
                  switch nDigits(i+1)
                      case 0
                          wordArray{i} = 'Ten ';
                          f = 2;
                      case 1
                          wordArray{i} = 'Eleven ';
                          f = 2;
                      case 2
                          wordArray{i} = 'Twelve ';
                          f = 2;
                      case 3
                          wordArray{i} = 'Thirteen ';
                          f = 2;
                      case 4
                          wordArray{i} = 'Fourteen ';
                          f = 2;
                      case 5
                          wordArray{i} = 'Fifteen ';
                          f = 2;
                      case 6
                          wordArray{i} = 'Sixteen ';
                          f = 2;
                      case 7
                          wordArray{i} = 'Seventeen ';
                          f = 2;
                      case 8
                          wordArray{i} = 'Eighteen ';
                          f = 2;
                      case 9
                          wordArray{i} = 'Nineteen ';
                          f = 2;
                  end
              case 2
                  wordArray{i} = 'Twenty ';
              case 3
                  wordArray{i} = 'Thrirty ';
              case 4
                  wordArray{i} = 'Fourty ';
              case 5
                  wordArray{i} = 'Fivty ';
              case 6
                  wordArray{i} = 'Sixty ';
              case 7
                  wordArray{i} = 'Seventy ';
              case 8
                  wordArray{i} = 'Eighty ';
              case 9
                  wordArray{i} = 'Ninety ';
          end
      elseif length(nDigits) >= 1 && f ==0;
          f = 1;
          switch nDigits(i)
              case 0
                  wordArray{i} = '';
              case 1
                  wordArray{i} = 'one';
              case 2
                  wordArray{i} = 'two';
              case 3
                  wordArray{i} = 'three';
              case 4
                  wordArray{i} = 'four';
              case 5
                  wordArray{i} = 'five';
              case 6
                  wordArray{i} = 'six';
              case 7
                  wordArray{i} = 'seven';
              case 8
                  wordArray{i} = 'eight';
              case 9
                  wordArray{i} = 'nine';
          end
          % double digits for teens
      elseif length(nDigits) >= 4 && f ==2;
          f = 1;
          wordArray{i} = '';
      end
      wordArray = strjoin(wordArray);
end
end

If you actually read all of this then you are a boss. I am sure that there is a more efficient way to do this; I am just starting with matlab.

  2 comentarios
Stephen23
Stephen23 el 24 de Nov. de 2016
@David Davis: if you want to check the output of your function, then you can compare with the output of my FEX submission:
I wrote my code to take into account many edge cases (arising from grammatical rules and from the limits of numeric calculations). My code was also tested on thousands of test cases, collected from online sources and other references.

Iniciar sesión para comentar.

Respuestas (2)

Image Analyst
Image Analyst el 24 de Nov. de 2016
Get rid of
wordArray = [' ':length(nDigits):' '];
wordArray = cellstr(wordArray);
Use this:
wordArray = cell(1,20);
And at the bottom of the function get rid of
wordArray = strjoin(wordArray);
and have this instead:
w = wordArray{:}
It will run without error, though it gives you the wrong answer still. I assume you can figure it out after that though.
  2 comentarios
David Davis
David Davis el 24 de Nov. de 2016
Thank you! but it still doesn't work. for both methods they work with a single digit input but as soon as the input goes double digit or larger it stops working.
Guillaume
Guillaume el 24 de Nov. de 2016
Yes, wordArray = [' ':length(nDigits):' ']; doesn't work. I assume it's meant to be wordArray = repmat(' ', numel(nDigits)); but as ImageAnalyst says, wordArray cell(1, 20) is a much simpler way of creating a cell array.
However, wordArray = strjoin(wordArray) is perfectly fine, and w = wordArray{:} will error. I assume IA meant w = [wordArray{:}] but unlike strjoin it won't put a space between each string.

Iniciar sesión para comentar.


Guillaume
Guillaume el 24 de Nov. de 2016
I don't understand the purpose of the extremely badly named a, b, ... f. Use meaningful variable names.
In any case, the best way for you to find what is going wrong is to use the debugger. Step through your program step by step and see if it does what you expected it to do. You'll quickly see where it goes wrong.
One thing I must say, seeing all these switch ... case fills me with horror. How about using array indexing instead:
digitwords = {'one', 'two', 'three', 'four', five', 'six', 'seven', 'eight', nine'}
wordArray{i} = digitwords(ndigits(i));
These two lines replace a whole switch ndgits{i} ... case ... case ... end
I would also work backwards from the units up to the first digit.
  3 comentarios
Stephen23
Stephen23 el 25 de Nov. de 2016
Editada: Stephen23 el 26 de Nov. de 2016
@David Davis: if you want to see one way of solving this task, see my function (which does exactly what you are trying to do). Note that my code has been extensively tested, and works correctly with many edge cases.
After much experimetnation and thought on how to achieve this, I ended up using MATLAB's ability to work with arrays, rather than using slower loops. In a nutshell: put the digits into a numeric matrix arranged by hundreds, tens, and ones, and then use this to index the correct text.
Guillaume
Guillaume el 25 de Nov. de 2016
Having thought about it a bit more, I wouldn't have a loop over the digits. Instead I would separate the digits in groups of three (starting from the end). For each group of three, I would call either the same function or a subfunction that would create the word string and when it returns append either the million, thousand or nothing. So it would look something like this:
function wordstring = num2word(number)
%example number = 1,234,567,890
split number into group of three. e.g. {1, 234, 567, 890}
reverse group order {890, 567, 234, 1}
thousands = {'', 'thousand', 'million', 'milliard'}; %using long-notation https://en.wikipedia.org/wiki/Long_and_short_scales
for groupidx = 1 : numel(group)
call subfunction(group{groupidx})
append thousands{groupidx}
end
end
function wordstring = subfunction(number)
%number is guaranteed to be less than 1000
ones = {'', 'One', 'Two', 'Three', 'Four', 'Five', 'Six', 'Seven', 'Eight', 'Nine'};
teens = {'Ten', 'Eleven', 'Twelve', 'Thirteen', 'Fourteen', 'Fifteen', 'Sixteen', 'Seventeen', 'Eighteen', 'Nineteen'};
tens = {'', '', 'ERROR', 'Twenty', 'Thirty', 'Fourty', 'Fifty', 'Sixty', 'Seventy', 'Eigthy', 'Ninety'};
decades = mod(number, 100);
if decades >= 10 && decades < 20
wordstring = teens(decades-9);
else
wordstring = strtrim(strjoin(tens{floor(decade / 10), ones(mod(decade, 10))));
end
if number >= 100
wordstring = strjoin(floor(number / 100), 'hundred', wordstring)
end
end

Iniciar sesión para comentar.

Categorías

Más información sobre Data Import and Analysis en Help Center y File Exchange.

Community Treasure Hunt

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

Start Hunting!

Translated by