2013-12-18 2 views
2

Мне нужно объединить некоторые диапазоны.Объединить диапазоны с 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]}.

Есть ли вариант где-то для этого?

+0

Не могли бы вы привести пример, где это имеет значение? –

+0

Это важно с датами, но я хотел, чтобы это было просто. Если вы работаете с 1 по 11 января и с 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 определяет следующий контракт:

Реализации, которые выбирают для поддержки оных (Range) операции должны игнорировать> пустые диапазоны и сливаться подключенные диапазоны. Например:

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» диапазоны, с верхней границей множества к вашему фактическому UpperBound + 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)} 

EDIT

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

Это работает по назначению. '[1, 10]' и '[11, 15]' не считаются связанными с [docs] (http://docs.guava-libraries.googlecode.com/git-history/release/javadoc/com/google /common/collect/Range.html#isConnected(com.google.common.collect.Range)). Это явно указано в документе «RangeSet»: «Обратите внимание, что поведение 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() 
Смежные вопросы