Как преобразовать цикл for с множественными операторами в условиях if, elif в список пониманий - PullRequest
0 голосов
/ 06 апреля 2019
for i in range(len(q)):
        # q.remove(max(q))
        # maxi = max(q)

    if((q.index(max(q)))+3) in range(len(q)):
            return("Too chaotic")

    if((q.index(max(q)))+2) in range(len(q)):
            bribe = bribe + 2
            q.remove(max(q))
    elif ((q.index(max(q)))+1) in range(len(q)):
            bribe = bribe + 1
            q.remove(max(q))
    elif(q.index(max(q))) == (len(q)-1):
            q.remove(max(q))
 return(bribe)

Я хочу преобразовать вышеприведенный цикл for в понимание списка.Я пытался сделать

["Too chaotic" if((q.index(max(q)))+3) in range(len(q)) 
 bribe+2,q.remove(max(q)) if((q.index(max(q)))+2) in range(len(q))  
 else [bribe+2,q.remove(max(q)]  if((q.index(max(q)))+2) in range(len(q)) 
 else q.remove(max(q)) if (q.inde  (max(q))) == (len(q)-1) for i in 
 range(len(q))]

, но это не сработало.

1 Ответ

0 голосов
/ 14 апреля 2019

В SO есть десятки таких вопросов: как я могу превратить этот кусок кода в понимание списка / слова?Я видел три основные цели:

  • производительность: кто-то хочет увеличить скорость или уменьшить объем памяти кода;
  • выразительность: кто-то хочет сжатый и понятный код;
  • обучение / веселье / экспериментирование: каждый хочет узнать о постижении списка самостоятельно.

Но иногда мы просто не знаем.Это именно тот случай, поэтому я начну с общих мыслей.

Вот мои эмпирические правила, прежде чем создавать понимание списка, в порядке важности:

  1. Начните счистый код, потому что понимание списка не сделает ваш код чище (на самом деле это, скорее всего, совсем наоборот)
  2. Убедитесь, что вы хотите создать список или агрегатная функция списка (сумма, максимум, ...)
  3. Убедитесь, что поток управления вашего кода не использует переходы (return, break, raise, ...)
  4. Убедитесь, что вы не выполняете никаких побочных эффектов.

Давайте попробуем использовать эти правила для решения вашего вопроса.

Очистите код

Первоеисправить это тип возвращаемого значения.В зависимости от ситуации вы возвращаете либо строку, либо целое число.Несмотря на то, что Python не предписывает функции для обеспечения согласованности, вам следует избегать такой путаницы.Вы можете либо вернуть специальное значение (-1), либо вызвать исключение.

Вот еще несколько вещей, которые нужно исправить:

Вы получите:

for _ in range(len(q)):
    m = max(q)
    max_q_index = q.index(m) # position of the max
    if max_q_index < len(q) - 3:
        return -1

    if max_q_index < len(q) - 2:
        bribe = bribe + 2
        q.remove(m)
    elif max_q_index < len(q) - 1:
        bribe = bribe + 1
        q.remove(m)
    elif max_q_index == len(q)-1:
        q.remove(m)
    # no else since max_index < len(q)

Это лучше, но этоможет быть улучшена.На самом деле у вас есть четыре разных случая:

  • max_q_index == len(q)-1
  • max_q_index == len(q)-2
  • max_q_index == len(q)-3
  • max_q_index < len(q)-3

Вы должны заменить <, чтобы выразить это.В трех первых случаях вы удаляете максимум из q:

for _ in range(len(q)):
    m = max(q)
    max_q_index = q.index(max(q)) # position of the max
    if max_index < len(q) - 3:
        return -1

    if max_index == len(q) - 3:
        bribe = bribe + 2
    elif max_index == len(q) - 2:
        bribe = bribe + 1
    q.remove(m)

Теперь мы понимаем, что происходит: если список почти отсортирован, максимум всегда находится в трех последних элементах, и цикл повторяетсяпо каждому элементу q.Иначе ты сломаешься.Вы могли бы написать это так:

for _ in range(len(q)):
    m = max(q)
    max_q_index = q.index(m) # position of the max
    distance = len(q) - 1 - max_q_index
    if distance >= 3:
        return -1

    bribe += distance
    q.remove(m)

Должен ли я использовать понимание списка?

Вам нужна сумма расстояний, таким образом, правило 2 соблюдается, но поток управления использует скачки:вы возвращаетесь, как только distance >= 3 найден, и удаляете элементы из q на каждой итерации (побочный эффект). Здесь не следует использовать понимание списка.

Бонус

Вы можете использовать другую стратегию: сортировать значения вместе с их индексами:

>>> L = [1,2,4,3,7,5]
>>> list(zip(L, range(len(L))))
[(1, 0), (2, 1), (4, 2), (3, 3), (7, 4), (5, 5)]
>>> S = sorted(zip(L, range(len(L))))
>>> S
[(1, 0), (2, 1), (3, 3), (4, 2), (5, 5), (7, 4)]

Функция zip архивирует элементы списка и цифры 0,1,2,3,4 ..., т.е. их положение в списке.Мы сортируем производимые кортежи по значению.Теперь сравните второе значение кортежей (position) с текущим индексом кортежа: если позиция ниже или равна индексу, max не является последним элементом списка, и мы увеличиваем взятку;если позиция больше, чем индекс, максимальное значение является самым правым значением списка.

>>> bribe = 0
>>> for i, (_, pos) in enumerate(S):
...     distance = max(i - pos, 0)
...     if distance >= 3:
...         raise Exception() # can't return outside of a function.
...     bribe += distance
...
>>> bribe
2

При L = [1,2,7,3,4,5] вы получите исключение.

Если вы неДля быстрого доступа к distance >= 3 вы можете использовать понимание списка:

>>> L = [1,2,4,3,7,5]
>>> sum(max(i - pos, 0) for i, (_, pos) in enumerate(sorted(zip(L, range(len(L))))))
2
>>> L = [1,2,7,3,4,5]
>>> sum(max(i - pos, 0) for i, (_, pos) in enumerate(sorted(zip(L, range(len(L))))))
3

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

...