【问题标题】:Removing list items from list of tuples based on second item of tuple根据元组的第二项从元组列表中删除列表项
【发布时间】:2018-09-27 06:30:34
【问题描述】:

我有一个元组列表:

ap = [('unknown', (81, 717, 236, 562)), ('unknown', (558, 1033, 825, 765)), ('unknown', (96, 1142, 225, 1013)), ('Jenny', (558, 1033, 825, 765)), ('unknown', (477, 1233, 632, 1078)), ('unknown', (741, 1199, 868, 1070)), ('Garry', (53, 282, 182, 153)), ('Sam', (477, 1233, 632, 1078)), ('Chen', (593, 283, 779, 97)), ('Steve', (741, 1199, 868, 1070)), ('unknown', (53, 282, 182, 153)), ('Harry', (81, 717, 236, 562)), ('unknown', (593, 283, 779, 97))]

如果元组的第二项与任何其他元组相同,我想对其进行排序,然后将第一项的元组保留为“未知”,并删除第一项为“未知”的元组。输出应该是这样的:

ap = [('Harry',(81, 717, 236, 562)), ('Jenny', (558, 1033, 825, 765)), ('unknown', (96, 1142, 225, 1013)), ('Sam', (477, 1233, 632, 1078)), ('Steve', (741, 1199, 868, 1070)), ('Garry', (53, 282, 182, 153)), ('Chen', (593, 283, 779, 97))]

我试过这段代码:

for i in ap:
    for j in ap:
        if i[1] == j[1]:
            if i[0] == "unknown":
                del i
            else:
                del j

但它给出了这个错误:

Traceback (most recent call last):
  File "<stdin>", line 3, in <module>
NameError: name 'i' is not defined

这有什么问题?

【问题讨论】:

  • 您正在删除j 循环中的i,当j 再次循环返回时,它找不到i,因为它将在j 循环完成后重新初始化。

标签: python python-3.x tuples


【解决方案1】:

这里简短的回答:列表理解

ap = [    ('unknown', (81, 717, 236, 562)), 
          ('unknown', (558, 1033, 825, 765)), 
          ('unknown', (96, 1142, 225, 1013)), 
          ('Jenny', (558, 1033, 825, 765)), 
          ('unknown', (477, 1233, 632, 1078)), 
          ('unknown', (741, 1199, 868, 1070)), 
          ('Garry', (53, 282, 182, 153)), 
          ('Sam', (477, 1233, 632, 1078)), 
          ('Chen', (593, 283, 779, 97)), 
          ('Steve', (741, 1199, 868, 1070)), 
          ('unknown', (53, 282, 182, 153)), 
          ('Harry', (81, 717, 236, 562)), 
          ('unknown', (593, 283, 779, 97))]

known = [my_tuple[1] for my_tuple in ap if my_tuple[0] != "unknown"]
output = [my_tuple for my_tuple in ap if (my_tuple[1] in known and my_tuple[0] != "unknown") or my_tuple[1] not in known]

print(output)

然后输出是:

[('unknown', (96, 1142, 225, 1013)), ('Jenny', (558, 1033, 825, 765)), ('Garry', (53, 282, 182, 153)), ('Sam', (477, 1233, 632, 1078)), ('Chen', (593, 283, 779, 97)), ('Steve', (741, 1199, 868, 1070)), ('Harry', (81, 717, 236, 562))]

这里发生的事情是我们将所有第二个元组元素收集到一个名称不是“未知”的列表中(使用列表理解)。

然后我们再次使用列表推导首先添加第二个元素已知且名称不是“未知”的所有元组,然后我们添加任何真正的未知数。

这可能听起来令人困惑,希望你明白我的意思。如果您有任何问题,请告诉我。

【讨论】:

  • 它帮助我做了一个单行:output = [my_tuple for my_tuple in ap if (my_tuple[1] in [my_tuple[1] for my_tuple in ap if my_tuple[0] != "unknown"] and my_tuple[0] != "unknown") or my_tuple[1] not in [my_tuple[1] for my_tuple in ap if my_tuple[0] != "unknown"]]
【解决方案2】:

del声明

删除名称会从本地或本地删除该名称的绑定 全局命名空间,取决于名称是否出现在全局中 同一代码块中的语句。如果名称未绑定,则会出现 NameError 将引发异常。

这个任务最好使用dictionary

expected = [('Harry',(81, 717, 236, 562)), ('Jenny', (558, 1033, 825, 765)),
('unknown', (96, 1142, 225, 1013)), ('Sam', (477, 1233, 632, 1078)),
('Steve', (741, 1199, 868, 1070)), ('Garry', (53, 282, 182, 153)), ('Chen', (593, 283, 779, 97))]


person_dict = {}

for person_name, person_val in ap:
    
    if person_val not in person_dict:
        # create key using tuple item 2
        person_dict[ person_val] =  person_name
    
    # key already exist so we only want to update its value if it is still unknown
    elif person_dict[ person_val] == 'unknown':
        person_dict[ person_val] =  person_name
        
        
ap = [(v,k) for k, v in person_dict.items()]

print(ap == expected) # True

【讨论】:

  • 这很聪明... +1 来自我
  • @SamGhatak 谢谢山姆 :)
【解决方案3】:

在两个循环中使用相同的集合并从循环内的集合中删除会在这里产生问题。我认为最好创建一个应删除的新项目列表并在此循环后将其删除。

toDelete = []
for i in ap:
    for j in ap:
        if i[1] == j[1] and not ap.index(i) == ap.index(j):
            if i[0] == "unknown":
                toDelete.append(i)
            else:
                toDelete.append(j)

for i in toDelete:
    try:
        ap.remove(i)
    except Exception as e:
        pass

try-catch 在那里,因为每个要更新的元素在 toDelete 中出现两次。

这可以通过将第二个循环设为:

for j in ap[ap.index(i)+1:]:

【讨论】:

    【解决方案4】:

    另一种方法是使用collections 在原始列表中创建重复的列表,然后通过检查哪个元素是重复的来创建新的元组列表。然后创建一个新列表,检查哪个元素不重复,或者哪个元素不是unknown

    import collections
    
    # Create a list of elements that are duplicate in the original list
    duplicates = [item for item, count in collections.Counter([x[1] for x in ap]).items() if count > 1]
    
    
    new = []
    for elem in ap:
        if elem[1] in duplicates:
            if elem[0] != 'unknown':
                # Copy the duplicate element only if it's not unknown
                new.append(elem)
        else:
    
            new.append(elem)
    print 'New list: ',new
    

    输出是:

    new list:  [('unknown', (96, 1142, 225, 1013)), ('Jenny', (558, 1033, 825, 765)), ('Garry', (53, 282, 182, 153)), ('Sam', (477, 1233, 632, 1078)), ('Chen', (593, 283, 779, 97)), ('Steve', (741, 1199, 868, 1070)), ('Harry', (81, 717, 236, 562))]
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-09-21
      • 2013-02-11
      • 2016-01-09
      • 1970-01-01
      • 2018-12-01
      • 2019-07-25
      • 2019-02-12
      相关资源
      最近更新 更多