Проверка того, что значение находится в наборе диапазонов
Нет необходимости генерировать и перебирать списки. Я подозреваю, что было бы более эффективно просто использовать операторы сравнения.
Однако, если вы хотите подтвердить, какой подход является наиболее эффективным, используйте инструменты профилирования.
Вот пример профилирования нескольких подходов к выяснению того, находится ли значение в пределах набора диапазонов, чтобы проверить, какой из подходов наиболее эффективен.
import cProfile
# Input data.
ranges = [[1, 5], [11, 14], [15, 19], [23, 30]]
values = [4, 14, 40]
# An implementation using a comparison operator (i.e. "<=").
def is_in_range_comparison_operator(v):
for r in ranges:
if r[0] <= v <= r[1]:
return True
return False
# An implementation using a range object.
def is_in_range_range_object(v):
for r in ranges:
if v in range(r[0], r[1]+1):
return True
return False
# An implementation using precomputed range objects.
range_objects = [range(r[0], r[1]+1) for r in ranges]
def is_in_range_precomputed_range_objects(v):
for r in range_objects:
if v in r:
return True
return False
# A list of the implementations, to make looping through them easier.
implementations = [
is_in_range_comparison_operator,
is_in_range_range_object,
is_in_range_precomputed_range_objects,
]
# A function to execute an implementation and print output.
def is_in_range(is_in_range_func):
print("Using {}:".format(is_in_range_func.func_name))
for v in values:
if is_in_range_func(v):
print ("True")
else:
print ("False")
print
# Run each implementation, printing out the results.
for f in implementations:
is_in_range(f)
# A function for executing a implementation repeatedly, for profiling purposes.
def test_is_in_range(is_in_range_func, num_iterations):
for _ in range(num_iterations):
for v in values:
if is_in_range_func(v):
pass
# Profile each implementation by running it num_iterations times.
num_iterations = 100000
for f in implementations:
command = "test_is_in_range({}, {})".format(
f.func_name, num_iterations)
print("Profiling the following command: {}".format(command))
cProfile.run(command)
А вот результат выполнения скрипта:
$ python in_range.py
Using is_in_range_comparison_operator:
True
True
False
Using is_in_range_range_object:
True
True
False
Using is_in_range_precomputed_range_objects:
True
True
False
Profiling the following command: test_is_in_range(is_in_range_comparison_operator, 100000)
300004 function calls in 0.388 seconds
Ordered by: standard name
ncalls tottime percall cumtime percall filename:lineno(function)
1 0.000 0.000 0.388 0.388 <string>:1(<module>)
1 0.172 0.172 0.388 0.388 in_range.py:51(test_is_in_range)
300000 0.212 0.000 0.212 0.000 in_range.py:8(is_in_range_comparison_operator)
1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects}
1 0.004 0.004 0.004 0.004 {range}
Profiling the following command: test_is_in_range(is_in_range_range_object, 100000)
1000004 function calls in 1.209 seconds
Ordered by: standard name
ncalls tottime percall cumtime percall filename:lineno(function)
1 0.000 0.000 1.209 1.209 <string>:1(<module>)
300000 0.639 0.000 1.033 0.000 in_range.py:15(is_in_range_range_object)
1 0.174 0.174 1.209 1.209 in_range.py:51(test_is_in_range)
1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects}
700001 0.396 0.000 0.396 0.000 {range}
Profiling the following command: test_is_in_range(is_in_range_precomputed_range_objects, 100000)
300004 function calls in 0.391 seconds
Ordered by: standard name
ncalls tottime percall cumtime percall filename:lineno(function)
1 0.000 0.000 0.391 0.391 <string>:1(<module>)
300000 0.220 0.000 0.220 0.000 in_range.py:23(is_in_range_precomputed_range_objects)
1 0.171 0.171 0.391 0.391 in_range.py:51(test_is_in_range)
1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects}
1 0.001 0.001 0.001 0.001 {range}
Некоторые выводы по результатам профилирования:
- Использование операторов сравнения более эффективно, чем многократное создание экземпляров объектов диапазона.
- Использование предварительно вычисленных объектов диапазона равнозначно использованию операторов сравнения.
Однако, если у вас есть огромное количество диапазонов для обработки, вероятно, будет более эффективно отказаться от использования объектов диапазона. Что приводит к...
Эффективная обработка произвольно большого набора диапазонов
Если ваш входной набор диапазонов достаточно велик, и вы беспокоитесь об исчерпании памяти, вот подход, который обрабатывает каждый диапазон по одному, проверяя все значения на соответствие этому диапазону.
Заметки:
- Подход заключается в обработке каждого диапазона по одному, сравнивая все значения с ним. Это позволяет обрабатывать произвольное количество диапазонов, не загружая их все заранее.
- Это не учитывает произвольное количество значений для поиска.
- Есть некоторые оптимизации, основанные как на входных диапазонах, так и на сортируемых значениях. Если нельзя полагаться на отсортированный ввод, оптимизация может быть соответствующим образом изменена или удалена.
ranges = [[4, 5], [11, 14], [15, 19], [23, 30]]
values = [4, 14, 20]
# Create a dictionary to keep track whether or not each value falls within
# a range, with a default value of False.
is_value_in_range = {}
def init_results():
global is_value_in_range
is_value_in_range = {v: False for v in values}
def print_values_and_results():
for v in values:
print("{}: {}".format(v, is_value_in_range[v]))
def check_for_values_in_range(r, values_index):
for i, v in enumerate(values[values_index:]):
# If the value is greater than the upper end of the range, move on
# to the next range.
if v > r[1]:
return (values_index + i, True)
# If the value is less than the lower end and we're on the last
# value, stop altogether.
if v < r[0] and values_index == len(values) - 1:
return (0, False)
if r[0] <= v <= r[1]:
is_value_in_range[v] = True
return (values_index, True)
def check_for_values_in_ranges(verbose=False):
init_results()
if verbose:
print("Initial results:")
print_values_and_results()
print
i = 0
for r in ranges:
i, continue_searching = check_for_values_in_range(r, i)
if verbose:
print("After checking range: {}".format(r))
print_values_and_results()
print
if not continue_searching:
break
print("Final results:")
print_values_and_results()
print
print("*** Check ranges for values (non-verbose) ***")
check_for_values_in_ranges()
print("*** Check ranges for values (verbose) ***")
check_for_values_in_ranges(True)
Вывод скрипта:
$ python large_input.py
*** Check ranges for values (non-verbose) ***
Final results:
4: True
14: True
20: False
*** Check ranges for values (verbose) ***
Initial results:
4: False
14: False
20: False
After checking range: [4, 5]
4: True
14: False
20: False
After checking range: [11, 14]
4: True
14: True
20: False
After checking range: [15, 19]
4: True
14: True
20: False
After checking range: [23, 30]
4: True
14: True
20: False
Final results:
4: True
14: True
20: False
person
chuckx
schedule
09.11.2019
range
в список, просто используйте объектrange
. Вот для чего они нужны. - person juanpa.arrivillaga   schedule 09.11.2019