Оценка вложенных целочисленных интервалов в Python

Этот вопрос касается интервального сравнения вложенных целочисленных интервалов.

Предположим, три диапазона целых чисел, которые я для простоты называю целевыми диапазонами. Эти целевые диапазоны никогда не перекрываются, но могут иметь разную длину.

> target1 = range(1,10000)
> target2 = range(10001,20000)
> target3 = range(20001,25000)

Далее предположим другой диапазон, который я называю тестовым диапазоном, который всегда имеет меньшую длину, чем любой из целевых диапазонов, но который может переходить в соседний целевой диапазон.

> test1 = range(900,5000)  # entirely in target1
> test2 = range(9900,10500)  # mostly in target2, but crosses into target1

Есть ли функция Python, которая помогает определить, в какие целевые диапазоны попадает тестовый диапазон? В случае, если испытательный диапазон пересекает соседний целевой диапазон, должен быть указан только тот целевой диапазон, на который приходится наибольшая часть испытательного диапазона.

> sought_function(test1, [target1, target2, target3])
# 1
> sought_function(test2, [target1, target2, target3])
# 2

ИЗМЕНИТЬ 1:

Какой код вы бы использовали при отсутствии стандартной функции Python для интервального сравнения вложенных целочисленных интервалов? Ниже приведен быстрый и неуклюжий код Python для функции под названием nested_in_which, которую, безусловно, можно улучшить.

def nested_in_which(test, targets):
    for n, t in enumerate(targets):
        if test[0] in t and test[-1] in t:
            return(n)
        else:
            if test[0] in t and n < len(targets) and test[-1] in targets[n+1]:
                return(n+1) # Overlap comparison not yet implemented

person Michael G    schedule 29.11.2016    source источник
comment
Нет, такой встроенной или стандартной библиотечной функции не существует.   -  person TigerhawkT3    schedule 29.11.2016
comment
@ TigerhawkT3 Достаточно честно. Можете ли вы порекомендовать некоторые библиотечные функции, которые сравнивают диапазоны целых чисел, что поможет мне сэкономить время при написании необходимого кода Python?   -  person Michael G    schedule 29.11.2016


Ответы (2)


Если вы думаете о каждом диапазоне как о наборе. Вам нужен целевой диапазон, который дает наибольшее пересечение с тестовым набором.

Итак, если вы вычисляете длину пересечения между каждой целью и тестом и возвращаете индекс максимального пересечения, у вас должно быть то, что вы хотите.

Вот примерный код, который это делает:

def which_range( testRange, *targetRanges ):
    testRange = set( testRange )
    tests = [ ( i, len( set( targetRange ).intersection( testRange ) ) ) for i, targetRange in enumerate( targetRanges ) ]
    return max( tests, key=lambda x: x[1] )[0]



>>> which_range( range(9900,10500), range(1,10000), range(10001,20000), range(20001,25000) )
1 # the second target range
>>> which_range( range(900,5000), range(1,10000), range(10001,20000), range(20001,25000) )
0 # the first target range
person Griffin    schedule 29.11.2016
comment
Отличное предложение! Однако ваш код заставляет пользователя явно вводить каждый тестовый диапазон, а не просто передавать список диапазонов. Не могли бы вы его адаптировать? - person Michael G; 29.11.2016
comment
@MichaelGruenstaeudl Это не заставляет. Они могут назвать это так: which_range( testRange, *someIterableOfRanges ) Вы должны найти документацию по синтаксису docs.python.org/2/tutorial/ - person Griffin; 29.11.2016
comment
@MichaelGruenstaeudl, если вы не хотите, чтобы сигнатура функции была такой, просто удалите * перед targetRanges, и это позволит вам передать итерацию, не распаковывая ее. - person Griffin; 29.11.2016
comment
Я понимаю. Спасибо за ваше объяснение. - person Michael G; 29.11.2016

Не уверен, что вы пытаетесь это сделать, но если вы хотите проверить, включен ли тестовый диапазон в целевой диапазон, вы можете сделать:

test1[0] in target1 and test1[-1] in target1
=> True
person Arount    schedule 29.11.2016
comment
Я обновил свой вопрос, чтобы проиллюстрировать свою цель. Похоже на функцию, которая выполняет типичную операцию; таким образом, я ожидал, что такая функция есть. - person Michael G; 29.11.2016