在 Python 中使用生成器/"with ... as" 的紧凑方式

Compact way using generators/"with ... as" in 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]

编辑:我正在寻找一个更通用的解决方案,我可以在其中使用具有任意长度子字符串的拆分字符串的任意索引,我只是使用了一个不正确的示例。查看我接受的解决方案。

为什么还要使用 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 限制为两次拆分以获得非常小的效率改进。)

一般情况是:

[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]

但是如果你有两个索引一个挨着另一个,这就太多了。

您可以使用:

[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)

以与您的示例类似的方法回答您的问题,并包括您的 :

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... 语法用于上下文管理器,其用途完全不同。不过,一个work-around就是要用for-loop解包。

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)