Guava记录 - 新集合类型RangeSet

2019-10-25  本文已影响0人  一点温柔

一、简介

Guava - RangeSet是Guava中新出的集合类型。官网对其描述如下:

A RangeSet describes a set of disconnected, nonempty ranges. When adding a range to a mutable RangeSet, any connected ranges are merged together, and empty ranges are ignored.

大致意思为:

RangeSet描述了一组断开连接、非空的Ranges.当将range添加到一个可变的RangeSet时,所有的ranges将会合并到一起,空的ranges将会被忽略.

可以理解为:

新出的RangeSet类型是一个操作数学应用中的区间的新集合类型.它可以存储多个非空区间.通过应用中的左闭右开左开右闭等规则,会将相连的区间merge成一个区间(多区间的并集操作),并且提供了这些区间的视图操作方法等.让我们遇到区间需求的业务代码时,开发起来更优雅、更方便.

值得注意的是:

GWT下不支持RangeSet,在JDK 1.5 backport中也不支持;RangeSet要求完全使用JDK 1.6中的NavigableMap特性,因此JDK的版本不得低于1.6.

二、常用方法

1、修改类型
a、增加元素方法 - add()

如同普通的Set集合一样,RangeSet也提供了添加集合元素的方法.不过此时元素的的类型被要求为区间元素Range.区间的类型可以分为开区间闭区间左开右闭左闭右开..

实验代码:

        System.out.println("====================测试 new collection Types====================");
        RangeSet<Integer> rangeSet = TreeRangeSet.create();
        // 添加闭区间{[1, 10]}
        rangeSet.add(Range.closed(1, 10));
        System.out.println("============测试输出添加一个闭区间之后的rangeSet===============" + rangeSet);
        // disconnected range: {[1, 10], [11, 15)}
        rangeSet.add(Range.closedOpen(12, 15));
        System.out.println("============测试输出添加一个左闭右开区间之后的rangeSet===============" + rangeSet);
        // connected range; {[1, 10], [11, 20)}
        rangeSet.add(Range.closedOpen(15, 20));
        System.out.println("============测试输出一个相邻左闭右开区间之后的rangeSet===============" + rangeSet);
        // empty range; {[1, 10], [11, 20)}
        rangeSet.add(Range.openClosed(25, 30));
        

实验结果:

====================测试 new collection Types====================
============测试输出添加一个闭区间之后的rangeSet===============[[1..10]]
============测试输出添加一个左闭右开区间之后的rangeSet===============[[1..10], [12..15)]
============测试输出一个相邻左闭右开区间之后的rangeSet===============[[1..10], [12..20)]
============测试输出添加一个左开右闭之后的rangeSet===============[[1..10], [12..20), (25..30]]
b、移除元素方法 - remove()removeAll()

如同普通的Set集合一样,RangeSet也提供了移除集合元素的方法.
remove(): 参数的的类型被要求为Range - 区间的类型可以分为开区间闭区间左开右闭左闭右开..
removeAll(): 参数的类型被要求为RangeSet.

实验代码:

        // splits [1, 10]; {[1, 5], [10, 10], [11, 20)}
        rangeSet.remove(Range.open(5, 10));
        System.out.println("============测试输出remove闭区间之后的rangeSet===============" + rangeSet);
        rangeSet.remove(Range.closed(11, 12));
        System.out.println("============测试输出remove闭区间之后的rangeSet===============" + rangeSet);
        rangeSet.remove(Range.openClosed(13, 14));
        System.out.println("============测试输出remove左开右闭之后的rangeSet===============" + rangeSet);
        rangeSet.remove(Range.closedOpen(15, 16));
        System.out.println("============测试输出remove左闭右开之后的rangeSet===============" + rangeSet);
        rangeSet.removeAll(TreeRangeSet.create());
        System.out.println("============测试输出removeAll之后的rangeSet===============" + rangeSet);

实验结果:

============测试输出remove闭区间之后的rangeSet===============[[1..5], [10..10], [12..20), (25..30]]
============测试输出remove闭区间之后的rangeSet===============[[1..5], [10..10], (12..20), (25..30]]
============测试输出remove左开右闭之后的rangeSet===============[[1..5], [10..10], (12..13], (14..20), (25..30]]
============测试输出remove左闭右开之后的rangeSet===============[[1..5], [10..10], (12..13], (14..15), [16..20), (25..30]]
============测试输出removeAll之后的rangeSet===============[[1..5], [10..10], (12..13], (14..15), [16..20), (25..30]]

2、视图类型

RangeSet还实现支持非常广泛的视图

a、获取补集 - complement()

如同数学应用中的区间操作一样,RangeSet支持获取当前集合区间中的补集.
complement()就是这样的一个方法。

值得一提的是: 补集也是一个RangeSet.

实验代码:

        System.out.println("==========测试complement方法==============" + rangeSet.complement());

实验结果:

==========测试complement方法==============[(-∞..1), (5..10), (10..12], (13..14], [15..16), [20..25], (30..+∞)]
b、获取与指定区间的交集 - subRangeSet(Range<C>)

RangeSet除了支持取补集的方法外,同样也支持取交集的方法.subRangeSet(Range<C>)就是这样一个获取交集的方法,不过它获取交集不是两个RangeSet之间取交集,而是指定一个Range与原有Range集合取交集.这泛化了传统排序集合的headSetsubSettailSet视图。

实验代码:

        //测试与指定range取交集
        System.out.println("==========测试subRangeSet方法==============" + rangeSet.subRangeSet(Range.closed(3, 5)));

实验结果:

==========测试subRangeSet方法==============[[3..5]]
c、迭代操作 - asRanges()

之前提到了RangeSet是多个Range区间的集合,那么当我们想对集合中的某些目标区间进行操作时,我们就需要用到asRanges()方法.

asRanges()RangeSet视为一个Range集合,让我们可以对其进行迭代操作。

实验代码:

System.out.println("==========测试元素所处范围asRanges()方法==============" + rangeSet.asRanges());
        rangeSet.asRanges()
                .stream()
                .filter(Objects::nonNull)
                .forEach(integerRange -> {
                    System.out.println("==========当前Range信息=========" + integerRange);
                    Integer testElement = NumberUtils.INTEGER_ONE;
                    System.out.println("===============当前Range是否包含测试节点========" + integerRange.contains(testElement));
                    System.out.println("===============当前Range最小节点============" + integerRange.lowerEndpoint());
                    System.out.println("===============当前Range最大节点============" + integerRange.upperEndpoint());
                    System.out.println("===============当前Range是否有上限============" + integerRange.hasUpperBound());
                    System.out.println("===============当前Range是否有下限============" + integerRange.hasLowerBound());
                });

实验结果:

==========测试元素所处范围asRanges()方法==============[[1..10], [12..20), (25..30]]

==========当前Range信息=========[1..10]
===============当前Range是否包含测试节点========true
===============当前Range最小节点============1
===============当前Range最大节点============10
===============当前Range是否有上限============true
===============当前Range是否有下限============true

==========当前Range信息=========[12..20)
===============当前Range是否包含测试节点========false
===============当前Range最小节点============12
===============当前Range最大节点============20
===============当前Range是否有上限============true
===============当前Range是否有下限============true

==========当前Range信息=========(25..30]
===============当前Range是否包含测试节点========false
===============当前Range最小节点============25
===============当前Range最大节点============30
===============当前Range是否有上限============true
===============当前Range是否有下限============true

可以看出通过迭代操作,输出了每一个区间所在的最小节点最大节点是否有上限是否有下限以及是否包含指定元素等信息.

3、查询类型

RangeSet除了支持我们上述的关于取交集补集迭代操作之外,还直接支持几个查询操作.

a、查询元素是否存在 - contains()

RangeSet中最常用的一个方法,查询整个RangeSet所有区间中是否包含了指定元素.如果包含返回true否则返回false.

实验代码:

        System.out.println("==========测试contains()方法==============" + rangeSet.contains(NumberUtils.INTEGER_ONE));
        System.out.println("==========测试contains()方法==============" + rangeSet.contains(NumberUtils.INTEGER_ZERO));

实验结果:

==========测试contains()方法==============true
==========测试contains()方法==============false
b、查询元素存在哪个区间 - rangeContaining()

有时我们的需求可能并不仅仅只是想知道元素是否存在,更想知道元素所在于哪个区间,这时就需要用到我们的rangeContaining()方法.rangeContaining()方法的作用就在于查询指定元素所在的Range,如果有符合的Range就将其返回,否则返回NULL.

实验代码:

        System.out.println("==========测试rangeContaining()方法==============" + rangeSet.rangeContaining(NumberUtils.INTEGER_ONE));
        System.out.println("==========测试rangeContaining()方法==============" + rangeSet.rangeContaining(NumberUtils.INTEGER_ZERO));

实验结果:

==========测试rangeContaining()方法==============[1..10]
==========测试rangeContaining()方法==============null
c、查询是否包含指定区间 - encloses()enclosesAll()

RangeSet也提供了验证指定区间是否包含在RangeSet集合中的方法.
encloses(): 查询RangeSet是否包含指定区间.
enclosesAll(): 查询RangeSet是否包含指定的RangeSet.

实验代码:

        //测试是否包含指定区间
        System.out.println("==========测试encloses()方法==============" + rangeSet.encloses(Range.closed(1, 5)));
        System.out.println("==========测试encloses()方法==============" + rangeSet.encloses(Range.closed(-1, 5)));
        
        //测试是否包含指定区间集
        System.out.println("==========测试enclosesAll()方法==============" + rangeSet.enclosesAll(TreeRangeSet.create()));
        System.out.println("==========测试enclosesAll()方法==============" + rangeSet.enclosesAll(rangeSet.complement()));

实验结果:

==========测试encloses()方法==============true
==========测试encloses()方法==============false

==========测试enclosesAll()方法==============true
==========测试enclosesAll()方法==============false
d、获取整个RangeSet边界的区间 - span()方法

除了上述的方法外,RangeSet还提供了一个比较有用的方法 - span(),它可以获取整个并集最大元素、最小元素作为边界的区间.

实验代码:

        System.out.println("==========测试all方法==============" + rangeSet);
        System.out.println("==========测试span()方法==============" + rangeSet.span());
        System.out.println("==========测试span()方法==============" + rangeSet.span().contains(11));

实验结果:

==========测试all方法==============[[1..10], [12..20), (25..30]]
==========测试span()方法==============[1..30]
==========测试span()方法==============true

......未完待续

上一篇下一篇

猜你喜欢

热点阅读