【问题标题】:Python - how to return list items from multiple lists of possible different lengths but get only non-matching pairs?Python - 如何从可能不同长度的多个列表中返回列表项,但只获得不匹配的对?
【发布时间】:2017-03-31 00:22:51
【问题描述】:

我有一个多行字符串如下:

mystr = """
ACTIVE     3/1.1 
IDLE       3/1.1 
IDLE       3/1.2 
IDLE       3/1.2 
ACTIVE     3/1.3 
IDLE       3/1.3 
ACTIVE     3/1.4 
IDLE       3/1.4 
ACTIVE     3/1.5 
ACTIVE     3/1.6 
IDLE       3/1.6 
ACTIVE     3/1.7 
IDLE       3/1.7 
ACTIVE     3/1.8 
IDLE       3/1.8 
ACTIVE     3/1.9 
IDLE       3/1.9 
IDLE       3/1.10
"""

或者用一个列表,它会是:

mylist = ['ACTIVE     3/1.1 ', 'IDLE       3/1.1 ', 'IDLE       3/1.2 ', 'IDLE       3/1.2 ', 'ACTIVE     3/1.3 ', 'IDLE       3/1.3 ', 'ACTIVE     3/1.4 ', 'IDLE       3/1.4 ', 'ACTIVE     3/1.5 ', 'ACTIVE     3/1.6 ', 'IDLE       3/1.6 ', 'ACTIVE     3/1.7 ', 'IDLE       3/1.7 ', 'ACTIVE     3/1.8 ', 'IDLE       3/1.8 ', 'ACTIVE     3/1.9 ', 'IDLE       3/1.9 ', 'IDLE       3/1.10 ']

我的目标是……

对于每一对“x/y.z”,例如 3/1.1 或 3/1.2 等,都应该有一个匹配的 ACTIVE 和 IDLE 对。

如果没有“ACTIVE”或“IDLE”配对,则检查配对是否都显示为 IDLE。如果是,请将其退回。 如果没有对,那么无论它显示为 ACTIVE 还是 IDLE,都返回该值。

我通过执行以下操作使其工作:

此 var 用于与 x/y.z 的某些值进行比较,其中“z”可以是 1 到 10 之间的任何值。但是,配对只匹配“x/y”。部分:

lc = ['3/1.', '3/2.', '3/3.', '3/7.', '3/8.', '4/1.', '4/5.', '4/6.', '4/7.', '5/3.', '5/4.', '5/5.', '6/1.', '6/2.', '6/3.', '6/7.', '6/8.', '7/1.']

然后我的脚本的其余部分有:

outputsum = ""
pri_list = [] 
sec_list = []
stable_list = []

for intf in mylist:
  for g60 in lc:
    if g60 in intf:
      if "ACTIVE" in intf:
        pri_list.append(intf)
      if "IDLE" in intf.text:
        sec_list.append(intf)

for p in pri_list:
  t1 = p[p.find("ACTIVE")+11:]
  for s in sec_list:
    t2 = s[s.find("IDLE")+11:]
    if t1 == t2:
      print "Found matching pair!"
      if "ACTIVE" in p and "IDLE" in s:
        print "Putting valid ACTIVE/IDLE pairs into stable_list."
        stable_list.append(p)
        stable_list.append(s)

for pair in stable_list:
  for p1 in pri_list:
    if p1 == pair:
      pri_list.pop(pri_list.index(p1))
  for s1 in sec_list:
    if s1 == pair:
      sec_list.pop(sec_list.index(s1))

for i in pri_list:
  outputsum += i + "\n"

for i in sec_list:     
  outputsum += i + "\n"

print outputsum
ACTIVE     3/1.5
IDLE       3/1.2
IDLE       3/1.2
IDLE       3/1.10

“打印输出总和”的输出是我期望得到的,但执行上述所有操作似乎很长/很复杂。

有没有更简单/更好/更快的方法来做到这一点?

我检查了许多不同的线程和示例,尝试了集合、交集和差异,以及与其他循环的混合,但我无法得到我想要的结果。在玩了几天之后,我终于想出了上面的工作示例。但我确信有比我上面的方法更好的方法。

有什么想法吗?

【问题讨论】:

    标签: python string list for-loop


    【解决方案1】:

    你可以使用defaultdict,见下文

    # Clean up the data
    j = [i.split('     ') for i in mylist]
    j[:] = [[jj[0], jj[1].strip()] for jj in j]
    
    
    # Make a list of idle/active for each key of "x/y.z"
    from collections import defaultdict
    d = defaultdict(list)
    for i in j:
        d[i[1]].append(i[0])
    
    
    # use some if/else to find pairing
    
    for k,j in d.items():
        if j == ['IDLE']:
            print 'IDLE at {}'.format(k)
        elif j == ['ACTIVE']:
            print 'ACTIVE at {}'.format(k)
        elif (j == ['ACTIVE', 'IDLE']) or (j == ['IDLE', 'ACTIVE']):
            print 'ACTIVE and IDLE at {}'.format(k)
    

    结果

    IDLE at 3/1.10
    ACTIVE and IDLE at 3/1.1
    ACTIVE and IDLE at 3/1.3
    ACTIVE and IDLE at 3/1.4
    ACTIVE at 3/1.5
    ACTIVE and IDLE at 3/1.6
    ACTIVE and IDLE at 3/1.7
    ACTIVE and IDLE at 3/1.8
    ACTIVE and IDLE at 3/1.9
    

    【讨论】:

    • 你可以只使用 i.split() 它将被多个空格分割为一个
    • @user1753919。谢谢!字典是我不太熟悉的另一个领域。我需要更多地使用字典。我没有想过为每个值对使用“x/y.z”键,这是有道理的。我认为这种方法可以很好地满足我的需要,因为“mylist”可能在每个项目中包含其他文本,但它总是有一个 x/y.z 值以及 ACTIVE 或 IDLE 或两者兼而有之。我可能可以更改 if/else 以在“j”中查找特定文本,如果匹配则打印“k”。
    • 另外,您如何阅读具有“j[:] = [[jj[0], jj[1].strip()] for jj in j]”之类的代码。我在其他线程中看到过这种类型的写作,当它在一行中时让我感到困惑。更常见的是,当有类似“(a for i in mylist if a == i)”时。不确定我提供的示例是否正确,但与它相似。
    • 它们被称为列表推导式,不再赘述,它们相当于在一行中编写for循环(偶尔使用if else)。它们使代码更简短,对于一直使用它们的人来说更易读,但对于不习惯它的人来说很难阅读。有几个关于列表推导的教程。还要检查 dict 理解。非常便利!就我而言,我正在制作一个列表列表,要查看列表列表,请在每个列表理解后使用 print j,你会看到我在做什么。
    • 感谢有关列表理解的信息。我会搜索那些教程。
    【解决方案2】:

    您可以使用 dastaframe groupby 功能。

    import pandas as pd 
    mylist = ['ACTIVE     3/1.1 ', 'IDLE       3/1.1 ', 'IDLE       3/1.2 ', 'IDLE       3/1.2 ', 'ACTIVE     3/1.3 ', 'IDLE       3/1.3 ', 'ACTIVE     3/1.4 ', 'IDLE       3/1.4 ', 'ACTIVE     3/1.5 ', 'ACTIVE     3/1.6 ', 'IDLE       3/1.6 ', 'ACTIVE     3/1.7 ', 'IDLE       3/1.7 ', 'ACTIVE     3/1.8 ', 'IDLE       3/1.8 ', 'ACTIVE     3/1.9 ', 'IDLE       3/1.9 ', 'IDLE       3/1.10 ']
    df= pd.DataFrame(mylist,columns =['one'])
    df = pd.DataFrame(df.one.str.split(' ',1).tolist())
    df.columns = [ 'act','num']
    res = [ item for item in df.set_index('num').groupby( lambda x:x.strip()[:6]) if len(item[1]) >1 ]
    

    【讨论】:

    • 谢谢!我从未使用过 pandas 模块。你所做的似乎很简单,所以我需要更多地了解 pandas 以更好地理解它。我尝试了您的代码,发现它添加了一列 act 和 num,但似乎对每一行都这样做。是否可以只做一次?
    【解决方案3】:

    我使用元组为你清理了它

    mylist = ['ACTIVE     3/1.1 ', 'IDLE       3/1.1 ', 'IDLE       3/1.2 ', 'IDLE       3/1.2 ', 'ACTIVE     3/1.3 ', 'IDLE       3/1.3 ', 'ACTIVE     3/1.4 ', 'IDLE       3/1.4 ', 'ACTIVE     3/1.5 ', 'ACTIVE     3/1.6 ', 'IDLE       3/1.6 ', 'ACTIVE     3/1.7 ', 'IDLE       3/1.7 ', 'ACTIVE     3/1.8 ', 'IDLE       3/1.8 ', 'ACTIVE     3/1.9 ', 'IDLE       3/1.9 ', 'IDLE       3/1.10 ']
    
    version_map = {}
    for status,version in (a.split() for a in mylist):
      if (version in version_map):
        version_map[version] = version_map[version] + (status,);
      else:
        version_map[version] = (status,);
    
    allowed_combos = [('ACTIVE',),('IDLE',),('IDLE','IDLE')];
    for versions,statuses in version_map.iteritems():
        if (statuses in allowed_combos):
          print versions,statuses;
    

    【讨论】:

    • 谢谢!这有帮助并且更短。我曾考虑过使用元组,但仍然不太了解如何使用它们。我需要更多地练习元组来掌握它。我唯一需要做的就是将结果元组转换为字符串。
    • 如果 mylist 在每个 x/y.z 对中有其他文本数据,例如“some data ACTIVE 3/1.10”并使用带 allowed_combos 的元组,则在“if (status in allowed_combos)”语句中,“状态”是否必须与 allowed_combos 完全匹配?我尝试通过在上面的示例中附加一个新的列表项来将其作为测试,但是在第一个 for 循环中出现“太多值无法解包”的错误。所以想知道这个例子是否更适合包含由空格分隔的两组字符串的列表,或者它是否可以与其他文本数据一起使用。
    • 此代码不处理无关字符串和清理,如果您希望处理这些情况,应在此代码块之前完成
    猜你喜欢
    • 2012-10-18
    • 2016-05-18
    • 2020-01-21
    • 2022-11-16
    • 2018-02-08
    • 1970-01-01
    • 1970-01-01
    • 2023-01-22
    • 2020-11-27
    相关资源
    最近更新 更多