【问题标题】:Python: Compare list of strings to list of tuples, and create a new list based on match or no matchPython:将字符串列表与元组列表进行比较,并根据匹配或不匹配创建一个新列表
【发布时间】:2016-01-02 00:12:22
【问题描述】:

我有一个字符串列表 a 和一个元组列表 b 其中:

a=['from src1 to dest2','from src3 to dest4','from src5 to dest6']
b=[['destb','dest2'],['destd','loc4'],['destf','dest6'],['desth','dest8']]

a 和 b 的长度可以不同且不相等。

我想遍历a,检查'dest'是否与每个元组中的第一个字符串匹配,如果匹配,则将其替换为第二个字符串,并将其附加到新列表中。如果未找到匹配项,我想将未更改的字符串追加到列表中。

所以它应该看起来像这样:

newlist=['from src1 to destb','from src3 to destd','from src5 to destf']

我当前的代码如下所示:

for source_dest_statement in source_dest_statements:
  for i,j in in source_dest_tuple:
    if j in source_dest_statement:
      amended_source_dest_statements.append('SOMETHING HAS CHANGED!')
      amended_source_dest_statements.append(re.sub(j,i,source_dest_statement))
    else:
      amended_source_dest_statements.append(source_dest_statement)

正如预期的那样,当没有匹配项时,这会重复附加当前迭代的 source_dest_statement,而我需要它们只出现在原始列表中出现的次数。解决此问题的最简单方法是什么?

编辑:我将尝试解释我要解决的问题:

我有一个防火墙配置,其中包含许多 NAT 语句。这些语句在更新版本的代码中发生了变化,因此在目标地址使用映射地址的地方,它们现在使用真实地址。

我的元组列表是映射地址对的真实地址列表。所以像 [(realaddress1,mappedaddress1),(r2,m2),(r3,m3)] 等等。

我有我想要通过的旧访问列表规则库,并将所有对映射地址的引用替换为对应的真实地址。

我正在尝试做的事情: - 遍历访问列表规则。 - 如果找到映射地址匹配,修改规则,附加到列表,插入说明规则已修改的注释。 - 如果未找到匹配项,则将现有规则附加到列表中。

编辑 - 解决方案

for/else 语句解决了我的问题。所以它看起来像这样: 对于一些列表中的currline: 对于 i,j 在某些情况下: 如果 j 在 curlline 中: newlistoflines.append(re.sub(j,i,currline)) 休息 别的: newlistoflines.append(currline)

感谢大家的帮助!我现在知道 break 语句并不邪恶,但我仍然想知道是否有更优雅的方法来解决我的问题。

【问题讨论】:

  • 我认为预期的新列表是错误的提供正确的预期输出
  • b 不是listtuples,而是listlists
  • 你说得对,我会修改@Joe R,我会修改我的例子。
  • “a”列表中的“dst6”是错字吗?好像应该是dest6。
  • 老实说,我认为你需要重新考虑你在做什么。这些不是解决这个问题的正确数据结构。你能问一个你想要解决的问题,而不是问我们你的解决方案吗?如果您提供更多详细信息,我认为我们可以为您提供更多帮助。不过由你决定。

标签: python string list list-comprehension


【解决方案1】:

编辑:

既然你说-

元组列表中的每个元组都需要在整个源/目标语句列表中进行搜索。

您可以将元素添加到结果列表中,然后在从元组中找到其中的元素时继续在其中进行替换。示例 -

for source_dest_statement in source_dest_statements:
    amended_source_dest_statements.append(source_dest_statement)
    for i,j in in source_dest_tuple:
        if j in amended_source_dest_statements[-1]:
            amended_source_dest_statements[-1]   = re.sub(j,i,amended_source_dest_statements[-1])

演示 -

>>> import re
>>> a=['from src1 to dest2','from src3 to dest4','from src5 to dest6']
>>> b=[['destb','dest2'],['destd','loc4'],['destf','dest6'],['desth','dest8']]
>>> result = []
>>> for x in a:
...     result.append(x)
...     for i,j in b:
...             if j in result[-1]:
...                     result[-1] = re.sub(j,i,result[-1])
...
>>> result
['from src1 to destb', 'from src3 to dest4', 'from src5 to destf']

以前的答案:

这就是 for..else 构造的用途。

您可以在for 循环的else: 部分添加将未更改的source_dest_statement 添加到amended_source_dest_statements 的语句。在第二个for 循环内的if 部分,您可以在找到匹配项后break 并将更改的结果添加到列表中。

for 循环的else 部分只有在您正常退出for 循环时才会执行,而不使用break 语句,因此当您找不到任何匹配项时就会出现这种情况。示例 -

for source_dest_statement in source_dest_statements:
    for i,j in in source_dest_tuple:
        if j in source_dest_statement:
            amended_source_dest_statements.append(re.sub(j,i,source_dest_statement))
    else:
        amended_source_dest_statements.append(source_dest_statement)

此外,正如 cmets 中所解释的,b 不是元组列表,而是列表列表(尽管对于您的特定用例并不重要)。

演示 -

>>> a=['from src1 to dest2','from src3 to dest4','from src5 to dst6']
>>> b=[['dest2','destb'],['dest4','locd'],['dest6','destf'],['dest8','desth']]
>>> result = []
>>> for x in a:
...     for i,j in b:
...         if i in x:
...             result.append(re.sub(i,j,x))
...             break
...     else:
...         result.append(x)
...
>>> result
['from src1 to destb', 'from src3 to locd', 'from src5 to dst6']

【讨论】:

  • 你说得对,我已经编辑了原始问题以反映我想要实现的目标。我已经尝试过 for/else 语句,但没有 break 语句。
  • 如果以上答案解决了您的问题。我想请您接受答案(通过单击答案左侧的勾号),这将对社区有所帮助。
  • 这不会导致元组中的第一个元素没有针对第一个列表中的其余行进行测试吗?元组列表中的每个元组都需要在整个源/目标语句列表中进行搜索。
  • 哦,好吧,等一下,让我稍微改一下逻辑
  • @TheStupidEngineer 如果问题已解决并且答案有帮助,我想请您接受答案(点击答案左侧的勾号),它会是对社区有帮助。
【解决方案2】:

如果在 b[0] 中找到 a 中的目标,则将 b[1] 代入 a 并将新字符串添加到结果中。如果没有替换,我们完成了它会输出原始内容。

result = []
for source in a:
    # Do all replacements with a list-comprehension
    replacements = [source.replace(old,new) for old, new in b if old in source]
    # If replacements we're done add the replacements else add the source
    if replacements:
        result.extend(replacements)
    else:
        result.append(source)

在您的测试输入中,它会输出以下内容:

['from src1 to destb', 'from src3 to locd', 'from src5 to destf']

【讨论】:

  • 你在正确的轨道上。如果找不到该值,我需要将 a 中的原始字符串附加到列表中。这就是我不确定如何构建循环的地方。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-01-09
  • 2020-05-26
  • 2020-02-24
  • 1970-01-01
  • 2021-11-18
  • 1970-01-01
相关资源
最近更新 更多