2013-12-18 45 views
2

我需要合併一些範圍。用番石榴合併範圍

我發現番石榴,看到它可以在某些情況下處理它。

RangeSet<Integer> rangeSet = TreeRangeSet.create(); 
rangeSet.add(Range.closed(1, 10)); // {[1, 10]} 
rangeSet.add(Range.closed(8, 15)); // {[1, 15]} 

現在,我要告訴番石榴,我需要的是[1, 10] + [11, 20] = {[1, 20]},而不是{[1, 10], [11, 20]}

有沒有一個選擇這個地方?

+0

你能提供一個例子,其中這個問題? –

+0

它與日期有關,但我想保持簡單。如果你從1月1日到11日以及1月12日到20日工作,你實際上從1日到20日工作。我需要將信息保存在我的應用程序中。 –

回答

8

如果你想這樣的範圍進行合併,你需要先規範化他們:

rangeSet.add(Range.closed(1, 10).canonical(DiscreteDomain.integers()); 
// {[1, 11)} 
rangeSet.add(Range.closed(11, 20).canonical(DiscreteDomain.integers()); 
// {[1, 21)} 
0

聲明:我不熟悉番石榴。

,你的上述兩個範圍不合並的原因是,有10和11之間的間隙要獲取範圍到你所需要的兩種情況之一結合:

  1. 的結束第一個範圍大於第二個範圍的開始。 (在上例中就是這種情況)

  2. 如果第一個和第二個範圍是相同的值,則它們都必須被視爲「打開」。 Guava documentation on ranges解釋瞭如何區分打開和關閉範圍。

0

我覺得TreeRangeSet實現是越野車。

RangeSet Guava javadoc定義了下面的合同:

實現,選擇支持add(範圍)操作需要忽略>空範圍和聚結連接範圍。例如:

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)} 
+4

這是按預期工作的。 [docs](http://docs.guava-libraries.googlecode.com/git-history/release/javadoc/com/google)不會考慮[1,10]和[11,15] /common/collect/Range.html#isConnected(com.google.common.collect.Range))。這在'RangeSet' doc中明確提到過:「請注意,Range.isEmpty()和Range.isConnected(Range)的行爲可能與離散範圍上的預期不符。」 –

+0

我同意,當我用isConnected doc的引用編輯我的答案時,您添加了您的評論;)但是,我仍然認爲文檔對於「[10,15)(15,20)」是錯誤的。 – ssssteffff

1
ImmutableRangeSet<Integer> rangeSet = ImmutableRangeSet.<Integer>builder() 
     .add(Range.closed(1, 10).canonical(DiscreteDomain.integers())) 
     .add(Range.closed(11, 15)) 
     .build()