4 views (last 30 days)

Hi community,

I noticed a problem with the following code:

year = '2001'

if year == '2000'

a = 1

elseif year == '2006' | year == '2007' | year == '2008' | year == '2009' | year == '2010' | year == '2011' | year == '2014' | year == '2015'

a = 2

end

Somehow this code gives out a = 2, which obviously is not wanted, as the conditions of the elseif line are not met.

If I just set one of the years as the elseif-condition without "|", the code does not give out a = 2, which is fine.

I know that I can use double numbers instead of strings, which works correctly.

So I don't need a solution, but an explanation, why this occurs...

Can you reproduce this false outcome?

Has matlab a general problem with strings in if conditions?

Or do I have an understanding problem how if-elseif works?

Stephen Cobeldick
on 7 Jan 2020

Edited: Stephen Cobeldick
on 7 Jan 2020

"So I don't need a solution, but an explanation, why this occurs..."

The first thing to do when trying to understand what your code is doing is to actually look at what your code is doing. Lets have a look at your logical comparison:

>> year = '2001';

>> year == '2000'

ans =

1 1 1 0

With character arrays == eq provides an element-wise comparison, so your 4x1 input character arrays return a 4x1 logical array, as the above example shows. Note how the last character of those two vectors are not the same, and hence the corresponding false in the output vector.

Now lets read the if documentation and see what it says about the conditional expression: " An expression is true when its result is nonempty and contains only nonzero elements (logical or real numeric). Otherwise, the expression is false." Consider your 4x1 logical vector: are all of its elements non-zero? (hint no, look at the last one). So your first if condition is NOT true.

You can do the same investigation with your

year == '2006' | year == '2007' | year == '2008' | year == '2009' | year == '2010' | year == '2011' | year == '2014' | year == '2015'

syntax yourself by looking at the resulting logical vector, just ,like I did. And then thinking about how that logical or operator works, and why at the end you will likely just end up with a basically meaningless 4x1 logical vector (which with your example data will contain all true values (and hence does satisfy the if condition)).

"...as the conditions of the elseif line are not met."

Wrong. Now that we have actually read the documentation and looked at your data, we now know that actually the if condition was met: you provided it with a 4x1 logical vector containing only true values.

Eventually you will reach the conclusion that this approach is rather unsuitable for what you are trying to achieve. The correct method is to use strcmp or strcmpi, e.g.:

if strcmp(year,'2006')

or for multiple character vectors use ismember or any wrapped around strcmp:

if ismember(year,{'2006','2007','2008'})

if any(strcmp(year,{'2006','2007','2008'}))

For completeness: if you are using strings (i.e. "") then you can use == to test for equivalence of each string array element, but I would recommend sticking with strcmp as this will give the same expected output for both scalar strings and character vectors, thus making your code more robust.

Walter Roberson
on 7 Jan 2020

year == '2000' is not comparing a single entity to another single entity.

'2001' is not a single entity: it is a character array with size 1 x 4. The test '2001' == '2000' is not checking that the entire "string" is identity: it is a vector test that compares ['2' == '2', '0' == '0', '0' == '0', '1' == '0] returning [true, true, true, false] . Then if [true, true, true, false] considers the condition to be false because at least one entry was false.

Likewise year == '2006' gives [true,true,true,false] and year == '2007' gives [true,true,true,false] . You have an | operation between those two vectors, so the result is [true|true, true|true, true|true, false|false] which gives [true, true, true, false] . And so on through year = '2009', continuing to get those [true, true, true, false] arrays. Then you reach the year == '2010' which is going to give you ['2'=='2','0'=='0,'0'=='1','1'=='0'] which is [true,true,false,false] . You or that with the [true,true,true,false] array you have been building to that point, getting [true|true,true|true,true|false,false|false] which is [true,true,true,false] -- even though the '0' of '01' did not equal the '1' of '10', the or with the previous true value gives true, allowing you to proceed. Now on to the year == '2011' test. ['2'=='2', '0'=='0', '0'=='1', '1'=='1'] which gives [true,true,false,true] . Now or that with the [true,true,true,false] you have been building up, and you get [true|true,true|true,true|false,false|true] and that gives [true,true,true,true] -- although the '0' of '01' does not match the '1' of '11', the or from the previous values gives true, and even though in all previous cases the fourth position was false, the true of comparing the final 1's gives true there, and now you have true in all positions. All of the remaining tests are or tests and they cannot give a false value because you already have all true. So you get to the end of the line with a [true,true,true,true] and if is happy with that because none of the entries are false.

If you want to thing of '2001' as a complete entity that should be compared as a whole to '2000' then you have three choices:

- You can switch to using strcmp() instead of == . Or
- You can switch to using ismember(year, {'2006', '2007', '2008' , '2009', '2010', '2011', '2014', '2015'}, 'rows') . Or
- R2017a or later, you can switch to string entities instead of character vectors:

year = "2001"

if year == "2000"

a = 1

elseif year == "2006" | year == "2007" | year == "2008" | year == "2009" | year == "2010" | year == "2011" | year == "2014" | year == "2015"

a = 2

end

I would suggest to you that using ismember() is easier to maintain.

Sign in to answer this question.

Opportunities for recent engineering grads.

Apply Today
## 0 Comments

Sign in to comment.