Переменная цикла разбиения списка

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

В качестве примера проблемы, которую я пытаюсь решить, у меня есть строка:

a = "1;2;4\n3;4;5"

И я хотел бы выполнить это:

>>> [(x.split(";")[1],x.split(";")[2]) for x in a.split("\n") if x.split(",")[1] != 5]
[('2', '4'), ('4', '5')]

Без необходимости бега расколоть три раза. Итак, что-то вроде этого (что, очевидно, является неверным синтаксисом, но, надеюсь, этого достаточно, чтобы донести сообщение):

[(x[1],x[2]) for x.split(";") in a.split("\n") if x[1] != 5]

В этом вопросе я не ищу причудливых способов получить 2-й и 3-й столбец строки. Это просто способ подать конкретный пример. Я мог бы для примера использовать:

[x.split(";")[1:3] for x in a.split("\n")]

Возможные решения, о которых я подумал:

  1. Не использовать понимание списка
  2. Оставь как есть
  3. Используйте csv.DictReader, назовите мои столбцы и что-то наподобие StringIO чтобы дать ему входные данные.

В большинстве случаев это хороший шаблон, который можно использовать, а не конкретный случай, поэтому сложно ответить на вопросы типа "почему вы хотите это сделать" или "что это за"?

Обновление: после прочтения приведенного ниже решения я пошел и провел несколько тестов скорости. И я обнаружил в своих самых базовых тестах, что предоставленное решение было на 35% быстрее, чем простое решение выше.

Ответ 1

Вы можете использовать понимание списка, обернутое вокруг выражения генератора:

[(x[1],x[2]) for x in (x.split(";") for x in a.split("\n")) if x[1] != 5]

Ответ 2

Начиная с Python 3.8 и введением выражений присваивания (PEP 572) (:= оператор), можно использовать локальную переменную в пределах понимания списка, чтобы избежать вызова дважды одного и того же выражения:

В нашем случае мы можем назвать оценку line.split(';') как переменную parts, используя результат выражения для фильтрации списка, если parts[1] не равно 5; и, таким образом, повторно использовать parts для получения сопоставленного значения:

# text = '1;2;4\n3;4;5'
[(parts[1], parts[2]) for line in text.split('\n') if (parts := line.split(';'))[1] != 5]
# [('2', '4'), ('4', '5')]