我需要合并一些范围。
我发现番石榴,看到它可以在某些情况下处理它。
RangeSet<Integer> rangeSet = TreeRangeSet.create();
rangeSet.add(Range.closed(1, 10)); // {[1, 10]}
rangeSet.add(Range.closed(8, 15)); // {[1, 15]}
现在,我需要告诉Guava我需要[1, 10] + [11, 20] = {[1, 20]}
而不是{[1, 10], [11, 20]}
。
这个地方有选择吗?
答案 0 :(得分:8)
如果你想要合并这样的范围,你需要先规范它们:
rangeSet.add(Range.closed(1, 10).canonical(DiscreteDomain.integers());
// {[1, 11)}
rangeSet.add(Range.closed(11, 20).canonical(DiscreteDomain.integers());
// {[1, 21)}
答案 1 :(得分:1)
ImmutableRangeSet<Integer> rangeSet = ImmutableRangeSet.<Integer>builder()
.add(Range.closed(1, 10).canonical(DiscreteDomain.integers()))
.add(Range.closed(11, 15))
.build()
答案 2 :(得分:0)
免责声明:我不熟悉番石榴。
你的两个范围之间的结合是因为10到11之间存在差距。要使范围合并,你需要以下两种情况之一:
第一个范围的结尾大于第二个范围的开头。 (以上例子就是这种情况)
如果第一个和第二个范围是相同的值,则必须同时考虑它们&#34;打开&#34;。 Guava documentation on ranges解释了如何区分开放范围和闭合范围。
答案 3 :(得分:0)
我认为TreeRangeSet
实施是错误的。
RangeSet Guava javadoc定义了以下合同:
选择支持add(Range)操作的实现需要忽略&gt;空范围并合并连接范围。例如:
RangeSet<Integer> rangeSet = TreeRangeSet.create();
rangeSet.add(Range.closed(1, 10)); // {[1, 10]}
rangeSet.add(Range.closedOpen(11, 15)); // disconnected range; {[1, 10], [11, 15)}
rangeSet.add(Range.closedOpen(15, 20)); // connected range; {[1, 10], [11, 20)}
rangeSet.add(Range.openClosed(0, 0)); // empty range; {[1, 10], [11, 20)}
rangeSet.remove(Range.open(5, 10)); // splits [1, 10]; {[1, 5], [10, 10], [11, 20)}
实际上TreeRangeSet
的实施执行以下操作(请注意[11, 20)
/ [11, 15), (15, 20)
的区别:
rangeSet.add(Range.closed(1, 10)); // {[1, 10]}
rangeSet.add(Range.closedOpen(11, 15)); // {[1, 10], [11, 15)}
rangeSet.add(Range.open(15, 20)); // disconnected range; {[1, 10], [11, 15), (15, 20)}
rangeSet.add(Range.openClosed(0, 0)); // empty range; {[1, 10], [11, 15), (15, 20)}
rangeSet.remove(Range.open(5, 10)); // splits [1, 10]; {[1, 5], [10, 10], [11, 15), (15, 20)}}
有几种情况:
[1, 10] + [11, 15)
未合并,但已连接...... [10, 15) + (15, 20)
未合并,这是正常的,因为它们已断开连接。但是,javadoc代码中的注释说它应该合并...... [10, 10] + [11, 20)
未合并,但已连接...... 我认为你能做到这一点的唯一方法就是添加“closedOpen”范围,上限设置为实际上限+ 1:
您可以使用@LouisWasserman'或者:
rangeSet.add(Range.closedOpen(1, 11)); // {[1, 11)}
rangeSet.add(Range.closedOpen(11, 21)); // {[1, 21)}
您还可以创建一种方法来“自动化”upperBound技巧,例如:
public void addRangeToSet(int lowerBound, int upperBound, RangeSet<Integer> set){
set.add(Range.closedOpen(lowerBound, upperBound + 1));
}
...
addRangeToSet(1, 10, set); // {[1, 11)}
addRangeToSet(11, 20, set); // {[1, 21)}
rangeSet.add(Range.closedOpen(1, 10)); // {[1, 10)}
rangeSet.add(Range.closedOpen(11, 20)); // {[1, 21)}
修改强>
请注意,某些离散范围不被视为连接,即使它们之间没有“元素”。例如,[3,5]不被认为与[6,10]相关联。在这些情况下,可能需要在测试连通性之前使用规范(DiscreteDomain)对两个输入范围进行预处理。
所以“最好的”方法似乎是@ LouisWesserman的一个:
rangeSet.add(Range.closed(1, 10).canonical(DiscreteDomain.integers()); // {[1, 11)}
rangeSet.add(Range.closed(11, 20).canonical(DiscreteDomain.integers()); // {[1, 21)}