【问题标题】:Comparing tuple values inside list of lists?比较列表列表中的元组值?
【发布时间】:2021-07-15 04:57:34
【问题描述】:

我有一个list,如下:

mylist=[[(1, 1)], [(1, 1), (1, 2)], [(1, 1), (1, 2), (1, 3)], [(1, 1), (1, 2), (1, 4)]]

现在,我想要的是将此列表中的每个元素与所有其他元素进行比较,如果该元素是与之比较的元素的子集,则应将其弹出。例如,[(1, 1)][(1, 1), (1, 2)] 的子集,则应从list 中弹出[(1, 1)]。同样,[(1, 1), (1, 2)][(1, 1), (1, 2), (1, 3)] 的子集,那么它也应该被弹出。

在这种情况下,我们得到如下输出:

[[(1, 1), (1, 2), (1, 3)], [(1, 1), (1, 2), (1, 4)]]

我尝试搜索所有可能的答案,但没有一个是针对这种特殊情况的。

到目前为止,我已经尝试了以下方法,但用处不大:

for i, e in enumerate(mylist):
mylist[i] = tuple(e)
mylist = list(set(mylist))

【问题讨论】:

    标签: python python-3.x list tuples


    【解决方案1】:

    您需要从mylist 中删除any 列表,其中all 列表中的元组存在于mylist 的另一个列表中。这最容易通过分配给一个新列表来完成:

    newlist = []
    for i, lst in enumerate(mylist):
        if not any(all(t in l for t in lst) for l in mylist[:i] + mylist[i+1:]):
            newlist.append(lst)
    

    或者作为列表理解:

    newlist = [lst for i, lst in enumerate(mylist) if not any(all(t in l for t in lst) for l in mylist[:i] + mylist[i+1:])]
    

    在这两种情况下,对于您的示例数据,输出为:

    [
     [(1, 1), (1, 2), (1, 3)],
     [(1, 1), (1, 2), (1, 4)]
    ]
    

    对于较大的列表,这可能会变慢,在这种情况下,您可以通过首先将 mylist 中的条目映射到集合来加快速度:

    mylist=[[(1, 1), (1, 2)], [(1, 1), (1, 2), (1, 3)], [(1, 1), (1, 2), (1, 4)], [(1, 1)]] 
    mylist=list(map(set, (tuple(l) for l in mylist)))
    newlist = [list(lst) for i, lst in enumerate(mylist) if not any(lst.issubset(l) for l in mylist[:i] + mylist[i+1:])]
    

    【讨论】:

      【解决方案2】:

      您可以使用frozenset.issubset 并像此示例一样进行比较:

      感谢@Nick 的建议,这是一个更详细的示例:

      mylist=[[(1, 1)], [(1, 1), (1, 2)], [(1, 1), (1, 2), (1, 3)], [(1, 1), 
      (1, 2), (1, 4)]] 
      out = [] 
      
      for k, elm in enumerate(mylist):  
         for elm2 in mylist[:k] + mylist[k + 1:]:  
             if frozenset(elm).issubset(elm2):  
                 break  
         else:  
             out.append(elm)    
      
      print(out)
      

      输出:

      [[(1, 1), (1, 2), (1, 3)], [(1, 1), (1, 2), (1, 4)]]
      

      【讨论】:

      • @ChihebNexus 您能否解释一下for 循环中发生的事情。我很难理解它。
      • @Junaid 我们遍历列表并获取当前索引。然后我们在同一个列表上再次循环,但我们删除了第一个循环的当前索引处的元素。然后我们将第一个循环的索引的第一个元素转换为forzenset 并使用issubset 方法来检查第一个元素是否是第二个元素的子集。
      【解决方案3】:

      @Nick 和 @ChihebNexus 的解决方案都没有效率。

      @Nick 的答案需要O(m ^ 2 xn ^ 2)的时间复杂度,而@ChihebNexus 的答案需要O(m ^ 2 xn)的时间复杂度,其中m是输入列表的长度,n是子列表的平均长度。

      对于只需要 O(mxn) 时间复杂度的方法,您可以创建一个 dict 将每个元组项目映射到该项目出现的一组子列表,保持请注意,这些子列表需要先转换为元组才能变为可散列并添加到集合中:

      mapping = {}
      for lst in mylist:
          for item in lst:
              mapping.setdefault(item, set()).add(tuple(lst))
      

      这样使用您的示例输入,mapping 变为:

      {(1, 1): {((1, 1),),
                ((1, 1), (1, 2)),
                ((1, 1), (1, 2), (1, 3)),
                ((1, 1), (1, 2), (1, 4))},
       (1, 2): {((1, 1), (1, 2), (1, 3)), ((1, 1), (1, 2)), ((1, 1), (1, 2), (1, 4))},
       (1, 3): {((1, 1), (1, 2), (1, 3))},
       (1, 4): {((1, 1), (1, 2), (1, 4))}}
      

      然后建立项目与其所属子列表的映射,然后我们可以再次遍历子列表,并获取当前子列表中的项目映射的子列表集合的交集to,以便找到包含当前子列表中所有项目的子列表。如果有多个这样的符合条件的子列表,则意味着当前子列表是其他符合条件的子列表的子集,我们可以通过将当前子列表从结果中删除其项目映射到的集合。在这个过程中幸存下来的子列表将是我们想要的输出,我们可以通过联合操作聚合集合来获得:

      for lst in mylist:
          if len(set.intersection(*map(mapping.get, lst))) > 1:
              t = tuple(lst)
              for item in lst:
                  mapping[item].remove(t)
      print(set.union(*mapping.values()))
      

      这个输出:

      {((1, 1), (1, 2), (1, 3)), ((1, 1), (1, 2), (1, 4))}
      

      如果您确实想要问题中的确切数据类型,可以将其转换为列表列表:

      list(map(list, set.union(*mapping.values())))
      

      返回:

      [[(1, 1), (1, 2), (1, 3)], [(1, 1), (1, 2), (1, 4)]]
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-06-24
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多