Удалить перекрывающиеся диапазоны из списка диапазонов Groovy

Мне нужно написать код, в котором у меня есть список диапазонов в Groovy. И мне нужно создать новый список из того, где все диапазоны не перекрываются.

Например, если ввод: [13..15, 14..16]

Я должен иметь возможность создать список, который имеет либо [13..16], либо [13..14, 14..16]

Буду очень признателен за любую помощь. На данный момент я написал следующий код, но он не работает:

def removeOverlapInRanges(ranges)
{
    def cleanedRanges = []
    def overLapFound = false
    def rangeIsClean = true
    def test = "ranges"
    ranges.each 
    {
        range->

        def index = ranges.indexOf(range)
        while (index < ranges.size() -1)
        {
            if (ranges.get(index + 1).disjoint(range) == false)
            {
                overLapFound = true
                rangeIsClean = false
                def nextRange = ranges.get(index + 1)
                if (range.from > nextRange.from && range.to < nextRange.to)
                    cleanedRanges.add(range.from..range.to)
                else if (range.from < nextRange.from && range.to < nextRange.to)
                    cleanedRanges.add(range.from..nextRange.to)
                else if (range.from > nextRange.from && range.to > nextRange.to)
                    cleanedRanges.add(nextRange.from..range.to)
            }
            index = index + 1
        }
        if (rangeIsClean)
            cleanedRanges.add(range)

        rangeIsClean = true

        test = test + cleanedRanges
    }
    cleanedRanges.add(0, cleanedRanges.get(cleanedRanges.size()-1))
    cleanedRanges.remove(cleanedRanges.size() - 1)
    if (overLapFound)
        return removeOverlapInRanges(cleanedRanges)
    else
        return cleanedRanges
}

Я прошел [12..13, 17..19, 18..22,17..19, 22..23,19..20 ]

А взамен я получил [12..13]

Спасибо заранее за любые данные!!


person user2119516    schedule 28.02.2013    source источник


Ответы (2)


Я получил это:

List<Range> simplify( List<Range> ranges ) {
  ranges.drop( 1 ).inject( ranges.take( 1 ) ) { r, curr ->
    // Find an overlapping range
    def ov = r.find { curr.from <= it.to && curr.to >= it.from }
    if( ov ) {
      ov.from = [ curr.from, ov.from ].min()
      ov.to   = [ curr.to, ov.to ].max()
      simplify( r )
    }
    else {
      r << curr
    }
  }
}

def ranges = [ 12..13, 17..19, 18..22, 17..19, 22..23, 19..20 ]
assert simplify( ranges ) == [ 12..13, 17..23 ]

ranges = [ -2..3, -5..-2 ]
assert simplify( ranges ) == [ -5..3 ]

ranges = [ 3..1, 1..5 ]
assert simplify( ranges ) == [ 5..1 ] // reversed as first range is reversed

ranges = [ 1..5, 3..1 ]
assert simplify( ranges ) == [ 1..5 ]

ranges = [ 1..5, 3..1, -1..-4 ]
assert simplify( ranges ) == [ 1..5, -1..-4 ]

ranges = [ 1..5, -6..-4, 3..1, -1..-4 ]
assert simplify( ranges ) == [ 1..5, -6..-1 ]

ranges = [ 1..3, 5..6, 3..5 ]
assert simplify( ranges ) == [ 1..6 ]

Хотя, вероятно, есть крайние случаи... Так что я проведу еще немного тестов...

person tim_yates    schedule 28.02.2013

Следующее с создайте простой список ваших уникальных номеров:

def ranges =  [12..13, 17..19, 18..22,17..19, 22..23,19..20 ];
def range = ranges.flatten().unique().sort()

Вот немного другой подход, который дает несколько хороших вспомогательных методов:

def parseToRangeString(range)
{
    String result = "";
    range.eachWithIndex{cur,i->
        def nex = range[i+1]
        def start = !result || result.endsWith(",")
        def cont = cur == nex?.minus(1)
        if (start && cont) //starting a new section and the next item continues this seq (starting a range = 1,10)
            result += "$cur-"
        else if (!cont && nex) //not continuing the seq and there are more nums to process (end with more = 6,8)
             result += "$cur,"
        else if (!cont && !nex) //not continuing the seq but there are no more nums to process (very end = 11)
            result += cur   
    }
    return result
}
def toRange(rangeStr)
{
    def ranges = rangeStr.split(",").collect{
        def range = it.split("-");
        new IntRange(range[0] as int, range[-1] as int)
    }
}
List.metaClass.toRangeString = {
    parseToRangeString(delegate)
}
List.metaClass.toRange = {
    def rangeStr = parseToRangeString(delegate)
    toRange(rangeStr)
}

def ranges =  [12..13, 17..19, 18..22,17..19, 22..23,19..20 ];
def list = ranges.flatten().unique().sort()
assert "12-13,17-23" == list.toRangeString()
assert [12..13,17..23] == list.toRange();
person purgatory101    schedule 28.02.2013