Google Guava 快速入门 —— 【新集合】RangeSet 类

Google Guava 快速入门.jpg

Guava RangeSet 类

一、类声明

@Beta
@GwtIncompatible
public interface RangeSet<C extends Comparable>

实现类:ImmutableRangeSetTreeRangeSet

二、接口方法

官方文档:https://google.github.io/guava/releases/27.0.1-jre/api/docs/com/google/common/collect/RangeSet.html

修饰符和类型方法描述
voidadd(Range<C> range) 
将指定范围添加到此RangeSet.
default voidaddAll(Iterable<Range<C>> ranges) 
将所有指定范围添加到此范围集
voidaddAll(RangeSet<C> other) 
将指定范围集中的所有范围添加到此范围集.
Set<Range<C>>asDescendingSetOfRanges() 
返回组成此范围集的断开连接的范围的降序视图.
Set<Range<C>>asRanges() 
用Set<Range>表现RangeSet,这样可以遍历其中的Range。.
voidclear() 
Removes all ranges from this RangeSet (optional operation).
RangeSet<C>complement() 
返回RangeSet的补集视图。complement也是RangeSet类型,包含了不相连的、非空的区间。
booleancontains(C value) 
RangeSet最基本的操作,判断RangeSet中是否有任何区间包含给定元素。
booleanencloses(Range<C> otherRange) 
简单明了,判断RangeSet中是否有任何区间包括给定区间。
default booleanenclosesAll(Iterable<Range<C>> other) 
如果对于其他成员范围,则返回true,在此范围集中存在包含它的成员范围.
booleanenclosesAll(RangeSet<C> other) 
如果对于其他成员范围,则返回true,在此范围集中存在包含它的成员范围.
booleanequals(@Nullable Object obj) 
如果obj是根据Range.equals(Object)包含相同范围的另一个RangeSet,则返回true。
inthashCode() 
返回 asRanges().hashCode().
booleanintersects(Range<C> otherRange) 
如果此范围集中的成员范围和指定范围都包含非空范围,则返回true.
booleanisEmpty() 
如果此范围集不包含范围,则返回true。
Range<C>rangeContaining(C value) 
返回包含给定元素的区间;若没有这样的区间,则返回null。
voidremove(Range<C> range) 
从此RangeSet中删除指定的范围.
default voidremoveAll(Iterable<Range<C>> ranges) 
从此范围集中删除所有指定范围.
voidremoveAll(RangeSet<C> other) 
从此范围集中删除指定范围集中的所有范围.
Range<C>span() 
返回包括RangeSet中所有区间的最小区间。
RangeSet<C>subRangeSet(Range<C> view) 
返回RangeSet与给定Range的交集视图。这扩展了传统排序集合中的headSet、subSet和tailSet操作。
StringtoString() 
返回此范围集的可读字符串表示形式。

三、使用

RangeSet 类是一个接口,需要用它的子类来声明一个 RangeSet 型的对象,实现 RangeSet 接口的类有 ImmutableRangeSet和 TreeRangeSet,ImmutableRangeSet 是一个不可修改的 RangeSet,而 TreeRangeSet 是利用树的形式来实现。下面主要谈 TreeRangeSet 的用法:

public void testRangeSet(){
    RangeSet rangeSet = TreeRangeSet.create();
    rangeSet.add(Range.closed(1, 10));
    System.out.println(rangeSet);   // [[1..10]]

    rangeSet.add(Range.closedOpen(11, 15));
    System.out.println(rangeSet);   // [[1..10], [11..15)]

    rangeSet.add(Range.open(15, 20));
    System.out.println(rangeSet);   // [[1..10], [11..15), (15..20)]

    rangeSet.add(Range.openClosed(0, 0));
    System.out.println(rangeSet);   // [[1..10], [11..15), (15..20)]

    rangeSet.remove(Range.open(5, 10));
    System.out.println(rangeSet);   // [[1..5], [10..10], [11..15), (15..20)]
}

上面函数的运行结果如下所示:

[[1..10]]
[[1..10], [11..15)]
[[1..10], [11..15), (15..20)]
[[1..10], [11..15), (15..20)]
[[1..5], [10..10], [11..15), (15..20)]

对 Range 类的方法不熟悉,请阅读之前文章

(1)遍历

那如果我们需要遍历rangeSet中的所有元素可以用下面方法实现

// 方法1
// rangeSet.asDescendingSetOfRanges().forEach(System.out::println);  // 倒序
Iterator<Range> iterator = rangeSet.asRanges().iterator();
while(iterator.hasNext()){
    Range next = iterator.next();
    System.out.println(next);
}

// 方法2
rangeSet.asRanges().forEach(System.out::println);

运行结果:

[1..5]
[10..10]
[11..15)
(15..20)

(2)互补范围

如果我们需要得到 rangeSet 互补的范围,我们可以用 RangeSet 提供的 complement() 方法,rangeSet.complement()同样是一个 RangeSet,其中的元素也是互不相交、且不为空的 RangeSet,那么 rangeSet 的互补集可以像下面这样来写:

RangeSet complement = rangeSet.complement();
System.out.println(complement);

得到的结果是:

[(-∞..1), (5..10), (10..11), [15..15], [20..+∞)]

正好是rangeSet的互补。

(3)包含

如果需要在 rangeSet 中查询某个元素是否在rangeSet中,可以用 contains(C) 来实现,其中 C extends java.lang.Comparable

比如我想得到上述rangeSet是否包含15,可以这样写:

boolean isIn = rangeSet.contains(15);
System.out.println(isIn);   // false,因为上述范围不包含元素15.

(4)查找范围

如果想知道某个元素是在rangeSet中哪个范围里面,可以这样写:

Range integerRange = rangeSet.rangeContaining(17);
System.out.println(integerRange);   // 输出 `(15..20)`,因为17被包含在 `(15..20)`中 ,所以输出这个范围。

如果想知道某个范围是否包含在rangeSet的范围中,可以这样写:

boolean encloses = rangeSet.encloses(Range.closedOpen(18, 20));
System.out.println(encloses);   // true.因为范围(18,20)包含在范围(15,20)中
encloses = rangeSet.encloses(Range.closedOpen(5, 20));
System.out.println(encloses);   // false 因为范围(5,20)不被rangeSet中任何范围包含.

RangeSet描述了一组不相连的、非空的区间。当把一个区间添加到可变的RangeSet时,所有相连的区间会被合并,空区间会被忽略。例如:

RangeSet<Integer> rangeSet = TreeRangeSet.create();
rangeSet.add(Range.closed(1, 10));      // {[1,10]}
rangeSet.add(Range.closedOpen(11, 15)); // 不相连区间:{[1,10], [11,15)}
rangeSet.add(Range.closedOpen(15, 20)); // 相连区间; {[1,10], [11,20)}
rangeSet.add(Range.openClosed(0, 0));   // 空区间; {[1,10], [11,20)}
rangeSet.remove(Range.open(5, 10));     // 分割[1, 10]; {[1,5], [10,10], [11,20)}

请注意,要合并 Range.closed(1, 10) 和 Range.closedOpen(11, 15) 这样的区间,你需要首先用 Range.canonical(DiscreteDomain) 对区间进行预处理,例如 DiscreteDomain.integers()

注:RangeSet不支持GWT,也不支持JDK5和更早版本;因为,RangeSet需要充分利用JDK6中NavigableMap的特性。

四、相关文章



未经允许请勿转载:程序喵 » Google Guava 快速入门 —— 【新集合】RangeSet 类

点  赞 (0) 打  赏
分享到: