1

I wrote a class that checks whether two integer intevals overlap. However I don't like this solution to much. I think that it's possible to do it in a better and simpler way.

public class IntegerInterval implements Interval {
private Integer start;
private Integer end;

public IntegerInterval(Integer start, Integer end) {
    this.start = start;
    this.end = end;
}

public Integer getStart() {
    return start;
}

public Integer getEnd() {
    return end;
}

public boolean isOverlapping(IntegerInterval other) {
    if (other != null) {
        return isInInterval(start, other) || isInInterval(end, other)
                || isInInterval(other.start, this) || isInInterval(other.end, this);
    }
    return false;
}

public boolean isInInterval(Integer number, IntegerInterval interval) {
    if (number != null && interval != null) {
        if(interval.getStart() == null && interval.getEnd() != null) {
            return number.intValue() <= interval.getEnd().intValue();
        }
        if(interval.getStart() != null && interval.getEnd() == null) {
            return number.intValue() >= interval.getStart().intValue();
        }
        if(interval.getStart() == null && interval.getEnd() == null) {
            return true;
        }
        return interval.getStart() <= number && number <= interval.getEnd();
    }
    else if(number == null && interval != null) {
        return interval.getStart() == null && interval.getEnd() == null;
    }
    return false;
}

}

BlueLettuce16
  • 2,013
  • 4
  • 20
  • 31
  • Interval [0, null] means [0,+infinity], Interval [null,null] means Interval [-infinity, + infinity]. I also have a bunch of unit tests that check, if it's necessary I'll post them too. – BlueLettuce16 Jan 08 '13 at 08:31
  • Why not just use `int` instead of `Integer`? Would save you all those null checks, and *if* you ever need a real `Integer` you can just let Java autobox the `int`... – fgysin Jan 08 '13 at 08:47
  • Because `int` cannot represent infinity. – Hui Zheng Jan 08 '13 at 09:51
  • Actually this is just simplification of my problem, the real problem is about java.util.Date. I think that I should have mentioned it in the first place. – BlueLettuce16 Jan 08 '13 at 10:28
  • You should write what do you mean by "better and simpler". As you see, there could be different views on it. Please, put explaining to your meaning and I'll remove the downvote. – Gangnus Jan 08 '13 at 13:08

3 Answers3

3

The following code should be simpler:

public boolean isOverlapping(IntegerInterval other) {
    if (other == null) return false; // for readability's sake, this condition is pulled out

    // overlap happens ONLY when this's end is on the right of other's start
    // AND this's start is on the left of other's end.
    return (((this.end == null) || (other.start == null) || (this.end.intValue() >= other.start.intValue())) &&
        ((this.start == null) || (other.end == null) || (this.start.intValue() <= other.end.intValue())));
}

UPDATE If compare by Date as @Adam actually asked, the code would be:

private static boolean dateRangesAreOverlaping(Date start1, Date end1,
                                               Date start2, Date end2) {
return (((end1 == null) || (start2 == null) || end1.after(start2)) &&
         ((start1 == null) || (end2 == null) || start1.before(end2)));

}

Hui Zheng
  • 10,084
  • 2
  • 35
  • 40
  • Thanks, I'll try it. I have also simplified my code a little bit. I think that I should mention in the first place that my problem does not concern Integers but Dates (java.util.Date). – BlueLettuce16 Jan 08 '13 at 10:25
  • Actually, my overlap algorithm can be generalized to any `Comparable` type including `Date`. – Hui Zheng Jan 08 '13 at 10:30
  • :) I thought that Integer/Date doesn't matter very much that's why I wrote about integers. – BlueLettuce16 Jan 08 '13 at 10:31
2

You should wrap start and end in a specific Comparable class that is able to encapsulate null. This way you only need to invoke compareTo in isInInterval and don't need to bother with null.

That class could also explicitly represent positive and negative infinity.

EDIT:
If you add a type parameter <T extends Comparable<T>> to the class declaration and declare the types of start and end type as Comparable<T> then you can use any type that implements Comparable with your Interval, not only Integer.

SpaceTrucker
  • 13,377
  • 6
  • 60
  • 99
  • Such a simple algorithm needs one more encapsulation? Won't you think that's overkilled? What's wrong with `null` in start as negative infinity and `null` in end as positive infinity? – Hui Zheng Jan 08 '13 at 09:27
  • @HuiZheng The OP asked how he could make his cleaner. One of the best ways to create clean code is to avoid null checks. The decision if this actually is overkill in his use case should be left to the OP. – SpaceTrucker Jan 08 '13 at 09:31
  • I agree that it's a nice solution, however I think that it's an overkill in this case. – BlueLettuce16 Jan 08 '13 at 10:26
  • @SpaceTrucker +1. Obviously, the author of the question means by "better and simpler" something else than we do. ;-) – Gangnus Jan 08 '13 at 13:04
  • Maybe it's just not my level yet ;/ – BlueLettuce16 Jan 24 '13 at 21:37
1

Assuming start < end. There should be 3 the checks for position of start relative to other: left, middle and right (right is for completeness as there is no intersection possible). So here are 2 remaining checks:

 (start <= other.start && end >= other.start) || 
 (start >= other.start && start <= other.end)  
 // start > other.end means no intersection as end > start > other.end

If you do checks for location of start as if than second chech can be just (start <= other.end):

 if (start <= other.start) return end >= other.start;
 else if (start <= other.end) return true;
 else return false;

Adjust "=" portions for your needs and add you null checks appropriately (i.e. use SpaceTrucker answer to make comaprison with null hidden inside class).

Alexei Levenkov
  • 98,904
  • 14
  • 127
  • 179