如何有效地交叉Guava Range和TreeSet?

时间:2013-01-28 22:03:18

标签: java guava

我想取一个集合和一个范围的交集,这样我得到一个包含不在该范围内的每个元素的集合。例如,我想从下面的代码段中获取setrange

import com.google.common.collect.*;

TreeSet<Integer> set = Sets.newTreeSet();
Collections.addAll(set, 1,2,3,5,11);
Range<Integer> range = Range.closed(4,10);

并返回一个仅包含5

的新TreeSet

1 个答案:

答案 0 :(得分:10)

在这个特定示例中,您最好不要使用Range,而是直接使用set.subSet(4, true, 10, true),但可能您的用例更复杂,而您的代码就是一个简化的示例。

除了自己处理所有案例之外别无选择。问题的一部分是NavigableSet可以使用任意Comparator,但Range(故意)仅适用于值类型的自然顺序,所以它有点尴尬在Guava中提供一个方法,它采用任意RangeNavigableSet并与它们相交。

最通用的解决方案看起来像......

if (range.hasLowerBound()) {
  if (range.hasUpperBound()) {
    return set.subSet(
      range.lowerEndpoint(),
      range.lowerBoundType() == BoundType.CLOSED,
      range.upperEndpoint(),
      range.upperBoundType() == BoundType.CLOSED);
  } else {
    return set.tailSet(
      range.lowerEndpoint(),
      range.lowerBoundType() == BoundType.CLOSED);
  }
} else {
  if (range.hasUpperBound()) {
    return set.headSet(
      range.upperEndpoint(),
      range.upperBoundType() == BoundType.CLOSED);
  } else {
    return set;
  }
}

那就是说,值得一提的是,如果你不关心效率,你可以Iterables.removeIf(set, Predicates.not(range))Sets.filter(set, range)