与番石榴合并范围

时间:2013-12-18 17:02:40

标签: java guava

我需要合并一些范围。

我发现番石榴,看到它可以在某些情况下处理它。

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]}

这个地方有选择吗?

4 个答案:

答案 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之间存在差距。要使范围合并,你需要以下两种情况之一:

  1. 第一个范围的结尾大于第二个范围的开头。 (以上例子就是这种情况)

  2. 如果第一个和第二个范围是相同的值,则必须同时考虑它们&#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)}

修改

isConnected method JavaDoc声明:

  

请注意,某些离散范围不被视为连接,即使它们之间没有“元素”。例如,[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)}