Понимание Python's itertools.chain и следующих
Я пытаюсь преобразовать строку кода Python в JavaScript, но я ограничен в знаниях Python и изо всех сил пытаюсь понять это.
Может кто-нибудь, пожалуйста, попробуйте объяснить следующую строку кода? point_orientation
функция не важна, она просто возвращает True/False.
i_extend = next( ( i for i in itertools.chain(range(i_start+1, len(p)), range(0,i_start+1)) if not point_orientation( p[i-1], p[i], p[(i+1) % len(p)] ) ) )
3 ответа
Значит "найди первый элемент" i
в range(i_start+1, len(p))
или же range(0,i_start+1)
(если в первом диапазоне нет такового) point_orientation( p[i-1], p[i], p[(i+1) % len(p)] )
ложно ". Если нет такого i
, это вызовет исключение.
Вот это в более подробном Python:
def check(i):
return point_orientation(p[i - 1],
p[i],
p[(i + 1) % len(p)])
def find_i_extend():
for i in range(i_start + 1, len(p)):
if not check(i):
return i
for i in range(0, i_start + 1):
if not check(i):
return i
i_extend = find_i_extend()
chain
сшивает два итератора в один. Здесь он используется для моделирования замкнутого цикла, начиная с определенной точки. Соблюдайте это
range(0, len(p)) == chain(range(0, i_start+1), range(i_start+1, len(p))
Данный код меняет местами аргументы chain
, так что он преобразует последовательность как [0,1,2,...,10]
в последовательности, как [5,6,...,10,0,1,...,4]
, Три аргумента для предиката являются просто смежными элементами в цикле, с (i+1) % len(p)
делать обтекание в конце последовательности. next
просто используется, чтобы получить первый элемент результирующей последовательности.
Если вы отказались от попыток выразить это в виде одной строки, вы могли бы написать более понятный код:
n = len(p)
for i in range(i_start + 1, i_start + 1 + n):
index_before = (i - 1) % n
index_at = i % n
index_after = (i+1) % n
if not point_orientation(p[index_before], p[index_at], p[index_after])
i_extend = y
break
Мы выполняем итерацию по одному диапазону и выполняем модульную арифметику для каждого индекса внутри цикла. Если предикат проходит, мы устанавливаем i_extend
к текущей точке и вырваться. В противном случае мы продолжим итерацию, предполагая, что одна из точек в конечном итоге будет успешной.
Здесь itertools.chain просто составляет список из обоих диапазонов, который может быть лучше выражен в этом контексте как (*range(i_start+1, len(p)), *range(i_start+1))
, (Распаковка: https://codeyarns.com/2012/04/26/unpack-operator-in-python/)
next()
просто получает "следующий" элемент итерируемого, и здесь, поскольку он работает непосредственно с выражением генератора, он служит для получения первого элемента; next(iter([1, 2, 3]))
Точно так же вернется 1
,
Таким образом, это может быть написано немного более идиотски, если это поможет -
next(i for i in (*range(i_start+1, len(p)), *range(i_start+1)) if not point_orientation(p[i-1], p[i], p[(i+1) % len(p)]))
-- или если next()
по-прежнему доставляет вам неприятности, вы можете вместо этого просмотреть его (обратите внимание на [0]
в конце):
[i for i in (*range(i_start+1, len(p)), *range(i_start+1)) if not point_orientation(p[i-1], p[i], p[(i+1) % len(p)])][0]