I have a method that gets a number of objects of this class
class Range
{
public T Start;
public T End;
}
In my case
Tossing another hat into the ring. Very much the same implementation as Gary W's (from which I got the sorted list approach), but done as a test case and with some helpful functions added to the Range class.
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Set;
import edu.emory.mathcs.backport.java.util.Collections;
import junit.framework.TestCase;
public class Range2Test extends TestCase {
public void testCollapse() throws Exception {
Set> set = new HashSet>();
set.add(new Range(1, 5));
set.add(new Range(3, 9));
set.add(new Range(11, 15));
set.add(new Range(12, 14));
set.add(new Range(13, 20));
Set> expected = new HashSet>();
expected.add(new Range(1, 9));
expected.add(new Range(11, 20));
assertEquals(expected, collapse(set));
}
private static > Set> collapse(Set> ranges) {
if (ranges == null)
return null;
if (ranges.size() < 2)
return new HashSet>(ranges);
ArrayList> list = new ArrayList>(ranges);
Collections.sort(list);
Set> result = new HashSet>();
Range r = list.get(0);
for (Range range : list)
if (r.overlaps(range)) {
r = r.union(range);
} else {
result.add(r);
r = range;
}
result.add(r);
return result;
}
private static class Range> implements Comparable> {
public Range(T start, T end) {
if (start == null || end == null)
throw new NullPointerException("Range requires start and end.");
this.start = start;
this.end = end;
}
public T start;
public T end;
private boolean contains(T t) {
return start.compareTo(t) <= 0 && t.compareTo(end) <= 0;
}
public boolean overlaps(Range that) {
return this.contains(that.start) || that.contains(this.start);
}
public Range union(Range that) {
T start = this.start.compareTo(that.start) < 0 ? this.start : that.start;
T end = this.end.compareTo(that.end) > 0 ? this.end : that.end;
return new Range(start, end);
}
public String toString() {
return String.format("%s - %s", start, end);
}
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + end.hashCode();
result = prime * result + start.hashCode();
return result;
}
@SuppressWarnings("unchecked")
public boolean equals(Object obj) {
if (this == obj) return true;
if (obj == null) return false;
if (getClass() != obj.getClass()) return false;
Range that = (Range) obj;
return end.equals(that.end) && start.equals(that.start);
}
public int compareTo(Range that) {
int result = this.start.compareTo(that.start);
if (result != 0)
return result;
return this.end.compareTo(that.end);
}
}
}