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

조회 수: 4 (최근 30일)
David Davis
David Davis 2016년 11월 24일
편집: Stephen23 2016년 11월 26일

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
Stephen23
Stephen23 2016년 11월 24일
@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.

댓글을 달려면 로그인하십시오.

답변 (2개)

Image Analyst
Image Analyst 2016년 11월 24일
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
David Davis
David Davis 2016년 11월 24일
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 2016년 11월 24일
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.

댓글을 달려면 로그인하십시오.


Guillaume
Guillaume 2016년 11월 24일
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
Stephen23
Stephen23 2016년 11월 25일
편집: Stephen23 2016년 11월 26일
@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 2016년 11월 25일
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

댓글을 달려면 로그인하십시오.

카테고리

Help CenterFile Exchange에서 Data Import and Analysis에 대해 자세히 알아보기

Community Treasure Hunt

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

Start Hunting!

Translated by