Компактный способ использования генераторов / "with ... as" в Python

У меня такая структура данных:

var = [['x_A_B', 1], ['x_A_C', 1], ['x_B_A', 1], ['x_B_D', 1], ['x_C_A', 1], ['x_C_D', 1], ['x_D_B', 1], ['x_D_C', 1]]

Я хотел бы извлечь эти значения как

var2 = [('A', 'B'), ('A', 'C'), ('B', 'A'), ('B', 'D'), ('C', 'A'), ('C', 'D'), ('D', 'B'), ('D', 'C')]

В настоящее время я использую следующую строку

var2 = [(item[0].split("_")[1], item[0].split("_")[2]) for item in var]

а писать утомительно, да еще и тот же split вычисляет два раза. Есть ли способ записать это компактно, может быть, с ключевыми словами with ... as, что-то вроде этого?

# not working
var2 = [(u, v) with item[0].split("_") as _, u, v for item in var]

Обновлено: Я искал более общее решение, в котором я мог бы использовать произвольные индексы разделенной строки с произвольной длиной подстрок, я просто использовал неподходящий пример. См. Решение, которое я принял.

item[0].split("_")[1:]
internet_user 19.03.2018 13:01
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
2
1
52
5
Перейти к ответу Данный вопрос помечен как решенный

Ответы 5

Зачем вообще использовать split? Вы знаете точные индексы букв, которые хотите.

>>> var = [['x_A_B', 1], ['x_A_C', 1], ['x_B_A', 1], ['x_B_D', 1], ['x_C_A', 1], ['x_C_D', 1], ['x_D_B', 1], ['x_D_C', 1]]
>>> [(x[0][2], x[0][4]) for x in var]
[('A', 'B'), ('A', 'C'), ('B', 'A'), ('B', 'D'), ('C', 'A'), ('C', 'D'), ('D', 'B'), ('D', 'C')]

I am interested in a more general case, suppose there can be 'x_word1_word2' variable names.

В этом случае internet_user дал вам решение в комментариях.

>>> var = [['x_A_B', 1], ['x_word1_word2']]
>>> [tuple(x[0].rsplit('_', 2)[1:]) for x in var]
[('A', 'B'), ('word1', 'word2')]

(Я использовал rsplit, ограниченный двумя разделениями, для очень незначительного повышения эффективности.)

Меня интересует более общий случай, допустим, могут быть имена переменных x_word1_word2.

Rolf 19.03.2018 13:04

В общем случае это будет:

[tuple(item[0].split('_')[1:3]) for item in var]

И самый общий случай:

indices = {1,2}
[tuple([x for i, x in enumerate(item[0].split('_')) if i in indices]) for item in var]

Но если у вас есть два индекса, расположенных один рядом с другим, это было бы слишком много.

Да, в данном случае это работает, @internet_user также предложил это. Но что делать, если нужные мне индексы не идут подряд, т.е. мне нужны 0 и 2?

Rolf 19.03.2018 13:10

@Rolf, ты все время меняешь вопрос, и, честно говоря, это начинает раздражать.

timgeb 19.03.2018 13:10

@timgeb Извините за это, я просто несколько раз сталкивался с этой проблемой, и меня интересовало очень общее решение. Но я признаю, что приведенный мною пример проще.

Rolf 19.03.2018 13:12

Ты можешь использовать:

[tuple(x[0].split('_')[1:]) for x in var]

out: [('A', 'B'), ('A', 'C'), ('B', 'A'), ('B', 'D'), ('C', 'A'), ('C', 'D'), ('D', 'B'), ('D', 'C')]

Другие ответы уже говорят о вашем конкретном случае. В более общем случае, если вы наблюдаете, что одно и то же значение появляется в понимании несколько раз ...

var2 = [(item[0].split("_")[1], item[0].split("_")[2]) for item in var]
        ^                       ^

и вы бы хотели избежать этого повторения. Это примерно так?

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

[(parts[1], parts[2] for item in var for parts in [item[0].split("_")]]
# or 
[(a, b) for item in var for (_, a, b) in [item[0].split("_")]]

но да, это не пройдет проверку кода ...

Как насчет того, чтобы вместо этого написать функцию?

def extract_parts(item):
    parts = item[0].split("_")
    return parts[1], parts[2]

[extract_parts(item) for item in var]
# or:
map(extract_parts, var)

Искал однострочное решение. Две написанные вами версии в порядке, но ответ, который я принял от abccd, немного яснее. По крайней мере, так работает мой мозг.

Rolf 19.03.2018 13:28

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

Kos 19.03.2018 13:41
Ответ принят как подходящий

Чтобы ответить на ваш вопрос с помощью подхода, аналогичного вашему примеру, и включая ваш комментарий:

Yes that works in this case, @internet_user also suggested this. But what if the indices I need are not consecutive, i.e. I need 0 and 2?

Синтаксис with...as... предназначен для диспетчеров контекста, который имеет совершенно другое применение. Однако можно обойтись без распаковки цикла for.

var = [['x_A_B', 1], ['x_A_C', 1], ['x_B_A', 1], ['x_B_D', 1], ['x_C_A', 1], ['x_C_D', 1], ['x_D_B', 1], ['x_D_C', 1]]

var2 = [(u, v) for item in var for _, u, v in (item[0].split("_"), )]

print(var2)

Я искал именно это.

Rolf 19.03.2018 13:21

Другие вопросы по теме