Home > Software design >  Shouldn't 2 subsequent 'If statements' be the equivalent of the logical 'and
Shouldn't 2 subsequent 'If statements' be the equivalent of the logical 'and

Time:12-13

How come these two outputs differ if 2 subsequent 'if' statements is the equivalent of saying "If statement 1 is true and statement 2 is true, return 'i'..

public int majorityElement(int[] nums) {
  if (nums.length == 1)
    return nums[0];
        
  HashMap<Integer, Integer> elements = new HashMap<>();
  for(int i : nums) {
    if(elements.containsKey(i) && (elements.get(i)  1 > nums.length / 2)) {
      return i;
    } else {
      elements.put(i, elements.getOrDefault(i,0)   1);
    }
  }
  return -999;
}

/*
  Input
  nums = [2,2,1,1,1,2,2]

  Output: 2
  Expected: 2
*/

Compared to this snippet:

public int majorityElement(int[] nums) {
  if (nums.length == 1)
    return nums[0];
        
  HashMap<Integer, Integer> elements = new HashMap<>();
  for (int i : nums) {
    if(elements.containsKey(i)){
      if(elements.get(i)  1 > nums.length / 2){
        return i;
      }
    } else {
      elements.put(i, elements.getOrDefault(i,0)   1);
    }
  }
  return -999;
}

/*
  Input
  nums = [2,2,1,1,1,2,2]

  Output: -999
  Expected: 2
*/

CodePudding user response:

Well, time to find a phone, you have a call to make.

The difference isn't in the if. Indeed, this:

if (a) {
  if (b) { foo(); }
}

is semantically identical to:

if (a && b) { foo(); }

even including the shortcircuiting behaviour (in both of those, if a resolves to false, expression b is not calculated at all. So if b has sideeffects, say its someMethod() where the method changes things or prints things, or it's a side-effect-having expression like c > 5 (which as a side effect, increments c), that method doesn't run, and c doesn't get incremented.

What's different is the else, though. Your first snippet does:

if (a) {
  if (b) { foo(); }
} else {
  bar();
}

and your second is:

if (a && b) foo();
else bar();

foo() is invoked only if both a and b. However, bar() in the first snippet is invoked if not a. Whereas in the second case it's invoked if not a or not b.

In your first snippet, it boils down to:

a=true a=false
b=true foo() bar()
b=false nothing happens bar()

your second one is subtly different:

a=true a=false
b=true foo() bar()
b=false bar() bar()

CodePudding user response:

It's AND in the sense that the code inside the block only execute if both conditions are true

if(elements.containsKey(i) && (elements.get(i)  1 > nums.length / 2)){
    return i;
}

same as

if(elements.containsKey(i)){
    if(elements.get(i)  1 > nums.length / 2){
        return i;
    }
}

But you also have an else statement, and the behavior is different for that part since the else is for the outer condition only:

if(!(elements.containsKey(i) && (elements.get(i)  1 > nums.length / 2))){
    elements.put(i, elements.getOrDefault(i,0)   1);
}

is not the same as

if(!(elements.containsKey(i)){
    elements.put(i, elements.getOrDefault(i,0)   1);
}

CodePudding user response:

The two techniques you provide are not at all equivalent. In the first example, it is possible that the following might happen:

elements.containsKey(i)  <-- true

elements.get(i)  1 > nums.length / 2  <-- false

In this case, neither the

return i

nor the

elements.put(i, elements.getOrDefault(i,0)   1);

Will be executed and your code will produce unexpected results. Hence your question here.

CodePudding user response:

Your first example has only two possible states:

if (a && b) {
  state 1 // your code returns, so you don't even need "else" in this case
} else {
  state 2 // your code updates the list
}

but your second example has three:

if (a) {
  if (b) {
    state 1 // the return call
  }
  state 3 // you do not have code here, so it "kicks in" but does nothing
} else {
  state 2 // the update call
}

So in a situation where a is true, but b is not, you hit state 3 instead of state 2, and because you have no code there, nothing happens:

  • we don't return so we stay in the function, and
  • we don't hit the else because a was true, so:

Nothing gets updated.

At every iteration of the loop we end up "doing nothing", the loop finishes, and we hit the end of the function where you return -999.

  • Related