Понимание 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]
Другие вопросы по тегам