简体   繁体   English

Python:将字符串列表与元组列表进行比较,并根据匹配或不匹配创建新列表

[英]Python: Compare list of strings to list of tuples, and create a new list based on match or no match

I have a list of strings a, and a list of tuples b where: 我有一个字符串列表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 and b can vary in length and be unequal. a和b的长度可以不同并且不相等。

I want to iterate through a, check if 'dest' matches the first string in each tuple, replacing it with the second string if it does, and append it to a new list. 我想迭代一遍,检查'dest'是否与每个元组中的第一个字符串匹配,如果是,则将其替换为第二个字符串,并将其附加到新列表中。 If no match is found, I want to append the string unchanged to the list. 如果找不到匹配项,我想将字符串不加改变地附加到列表中。

So it should look something like this: 所以看起来应该是这样的:

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

My current code looks like this: 我当前的代码如下所示:

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)

As expected, this repeatedly appends the currently iterated source_dest_statement when there are no matches, when I need them to only occur as many times as they were present in the original list. 正如预期的那样,当没有匹配时,这会反复追加当前迭代的source_dest_statement,当我需要它们只出现在原始列表中的次数时。 What would be the simplest way to fix this behaviour? 解决此问题的最简单方法是什么?

EDIT: I'll try to explain the problem I'm trying to solve: 编辑:我会尝试解释我试图解决的问题:

I have a firewall config which has a number of NAT statements. 我有一个防火墙配置,它有许多NAT语句。 These statements have changed in the updated version of code, so where destination addresses used mapped addresses, they now use real addresses instead. 这些语句在更新的代码版本中已更改,因此在目标地址使用映射地址的情况下,它们现在使用实际地址。

My list of tuples is a list of real address to mapped address pairs. 我的元组列表是映射地址对的实际地址列表。 So something like [(realaddress1,mappedaddress1),(r2,m2),(r3,m3)] and so on. 所以像[(realaddress1,mappedaddress1),(r2,m2),(r3,m3)]等等。

I have the old access list rulebase which I want to go through, and replace all the references to the mapped addresses with the corresponding real address. 我有旧的访问列表规则库,我想通过,并用相应的实际地址替换映射地址的所有引用。

What I'm trying to do: - Iterate through access list rules. 我正在尝试做什么: - 迭代访问列表规则。 - If a mapped address match is found, amend the rule, append to a list, insert a comment stating the rule has been modified. - 如果找到映射的地址匹配,则修改规则,附加到列表,插入注释,说明规则已被修改。 - If no match is found, append the existing rule to the list. - 如果未找到匹配项,请将现有规则附加到列表中。

EDIT - Solution 编辑 - 解决方案

The for/else statement solved my problem. for / else语句解决了我的问题。 So it looked something like this: for currline in somelist: for i,j in sometuple: if j in currline: newlistoflines.append(re.sub(j,i,currline)) break else: newlistoflines.append(currline) 因此它看起来像这样:对于某些列表中的currline:对于i,j在sometuple中:如果j在currline中:newlistoflines.append(re.sub(j,i,currline))break else:newlistoflines.append(currline)

Thanks for all of the help! 感谢您的帮助! I now know that the break statement is not something evil, but I'd still like to know if there is a more elegant way to solve my problem. 我现在知道break语句不是邪恶的东西,但我仍然想知道是否有更优雅的方法来解决我的问题。

EDIT : 编辑:

Since you say - 既然你说 -

Each tuple in the list of tuples needs to be searched for in the whole list of source/dest statements. 需要在整个source / dest语句列表中搜索元组列表中的每个元组。

You can add the element to the result list and then keep replacing inside it as you find elements in it from the tuple. 您可以将元素添加到结果列表中,然后在元组中找到元素时继续替换它。 Example - 示例 -

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

Demo - 演示 -

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

PREVIOUS ANSWER : 以前的答案:

This is what the for..else construct is for. 这就是for..else结构的用途。

You can add the statement to add the not-changed source_dest_statement into amended_source_dest_statements , in the else: part of the for loop. 您可以在for循环的else:部分中添加语句以将未更改的source_dest_statement添加到amended_source_dest_statements中。 And in the if part inside the second for loop, you can break once you find a match and add the changed result to the list. 在第二个for循环内的if部分中,一旦找到匹配就可以break ,并将更改后的结果添加到列表中。

The else part of a for loop is only executed if you exit the for loop normally, without using a break statement, hence that would be the case when you don't find any matches. for循环的else部分仅在正常退出for循环时执行,而不使用break语句,因此当您没有找到任何匹配时就是这种情况。 Example - 示例 -

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)

Also, as explained in comments, b is not a list of tuples, its a list of lists (Though does not really matter for your particular usecase). 另外,正如注释中所解释的那样, b不是元组列表,它是列表列表(虽然对于您的特定用例并不重要)。

Demo - 演示 -

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

If the destination in a is found in b[0], b[1] is substituted into a and the new string is added to the result. 如果在b [0]中找到a中的目的地,则将b [1]代入a,并将新字符串添加到结果中。 If no substitutions we're done it outputs the original instead. 如果我们没有完成替换,则输出原始代替。

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)

On your test input it outputs this: 在您的测试输入上,它输出:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM