Python在一次迭代中有条件地插入多个元素

2024-09-29 23:23:24 发布

您现在位置:Python中文网/ 问答频道 /正文

假设我们必须在一次迭代中在一个列表理解中插入两个元素,但是我们必须选择插入哪两个元素。我们如何才能做出这样的清单理解。在

为示例:- 假设我们有一个列表hostnames = ['aa', 'bb', 'dd', 'pp', 'bb', 'zz', 'hh']。在

现在我们要修改这个列表,使以p开头的主机名应该有一个名为“_prd”(例如“pp_prd”)的额外元素,对于以h开头、值为“_uat”的主机名也应该有一个额外的元素(例如“hh_uat”)。在

所以上面列表的期望输出是mod_hostnames = ['aa', 'bb', 'dd', 'pp_prd', 'pp', 'bb', 'zz', 'hh_uat','hh']。在

现在我想这样写-

>>> fh=lambda x: x+'_uat'
>>> fp=lambda x:x+'_prd'
>>> fo=lambda x:x
>>> lis
['aa', 'bb', 'dd', 'pp', 'bb', 'zz', 'hh']
>>> hostnames = lis
>>> mod_hostnames = [f(host) for f in (fo,fp) if host[0]=='p' else f(host) for f in (fo,fh) if host[0]=='h' else host for host in hostnames]
  File "<stdin>", line 1
    mod_hostnames = [f(host) for f in (fo,fp) if host[0]=='p' else f(host) for f in (fo,fh) if host[0]=='h' else host for host in hostnames]
                                                                 ^
SyntaxError: invalid syntax

我们得到一个语法错误。我还知道在列表理解中,第二个循环运行得更快(就像for循环一样),而在我们的代码中,host in hostnames运行得更快,而不是另一种所需的方式。所以我试了一下:

^{pr2}$

有什么建议吗?或者这在列表理解中是不可能的。
我知道这根本不可读,有更好的方法来写出来。(例如使用dict“switch”在for循环中的一个语句中写入此语句,或者在循环中使用旧的if-else语句,等等)。在

后解决方案编辑:收到了精彩的答复。谢谢!有人能解释一下为什么我发布的代码也是错误的吗?
我觉得这是因为当condition为true或false时计算的语句只会解析为一个空的for循环:for f in (fo,fp) if host[0]=='p' else for f in (fo,fh)如果host[0]=='p',程序将进入一个空的for循环for f in (fo,fp)。这是对的吗?
我想,把我错误的理解力逆向工程到for循环中,我想可以澄清这一点。在


Tags: inhost元素列表forifhhelse
3条回答

首先,您需要编写一个始终返回元组的转换函数,必要时使用单元组:

def transform(name):
    if name.startswith("p"):
        return (name + "_prd", name)
    if name.startswith("h"):
        return (name + "_uat", name)
    return (name,) # Singleton tuple.

然后你可以这样做:

^{pr2}$

itertools.chain.from_iterable本质上是一个连接所有中间元组的平坦操作,外部的list将该生成器的输出转换为实际的列表。在

然而,在这种情况下,使用传统的for循环的更普通的方法更有意义。在

你的想法还可以,但是你的语法不正确。以下是修改现有代码的方法:

mod_hostnames = [
    f(host) for host in hostnames 
    for f in (
        (fo,fp) if host.startswith('p') else 
        (fo,fh) if host.startswith('h') else 
        (fo,)
    )
]
print(mod_hostnames)
#['aa', 'bb', 'dd', 'pp', 'pp_prd', 'bb', 'zz', 'hh', 'hh_uat']

if/else括起来,用括号修改f的iterable,并且还需要(fo,)中的尾随逗号使其成为元组。在

也可以使用str.startswith,而不是为字符串中的第一个字符编制索引。在

在任何情况下,传统的循环在这里是完美的,并且为了可读性/易于理解,可能更可取:

^{pr2}$

实际上,最好从传统的for循环开始,这样您就可以大致了解困难所在:

mod_hostnames = []
for name in hostnames:
    if name.startswith('p'):
        r = [name + '_prd', name]
    elif name.startswith('h'):
        r = [name + '_uat', name]
    else:
        r = [name]
    mod_hostnames.extend(r)

assert mod_hostnames == ['aa', 'bb', 'dd', 'pp_prd', 'pp', 'bb', 'zz', 'hh_uat', 'hh']

要创建一个理解列表,您需要转换if。。。elif。。。else语句在一行语句中使用。。。if。。。else。。。在

您可以按如下方式处理:

^{pr2}$

嗯,这有点棘手。在

要将这个循环转换为一个理解列表,您需要迭代r值。你会在理解列表中得到一个理解列表。在

^{3}$

哼!我觉得写一份理解清单太复杂了。谁会想调试它呢?在

对于可维护性,我建议使用一个小功能的解决方案:

def modify(name):
    if name.startswith('p'):
        return [name + '_prd', name]
    elif name.startswith('h'):
        return [name + '_uat', name]
    else:
        return [name]


mod_hostnames = [item
                 for name in hostnames
                 for item in modify(name)]

在这里!在

相关问题 更多 >

    热门问题