python 根据另一个列表中的值从字典列表中删除项

pgvzfuti  于 2023-04-10  发布在  Python
关注(0)|答案(4)|浏览(118)

我有一份名单
items_to_delete = [(69, 70), (84, 88)]
我想从字典列表中删除所有startend值等于items_to_delete列表中元组的项。

input_list = 
[{'name': 'John', 'gender': 'male', 'start': 69, 'end': 70}, 
 {'name': 'Sara', 'gender': 'female', 'start': 75, 'end': 80},  
 {'name': 'George', 'gender': 'male', 'start': 84, 'end': 88},
 {'name': 'James', 'gender': 'male', 'start': 98, 'end': 101}]

预期输出为:

[{'name': 'Sara', 'gender': 'female', 'start': 75, 'end': 80},
 {'name': 'James', 'gender': 'male', 'start': 98, 'end': 101}]

到目前为止我所做的:

res = [dict_ent for dict_ent in input_list for item in items_to_delete if not (dict_ent['start']==item[0] and dict_ent['end']==item[1])]

但是它有我不想要的字典x1和我想要的字典x2。
如何使用列表解析实现预期的结果?谢谢!

vsikbqxv

vsikbqxv1#

你可以使用内置的operator.itemgetter来解决这个问题:

from operator import itemgetter

items_to_delete = [(69, 70), (84, 88)]
input_list = [
    {'name': 'John', 'gender': 'male', 'start': 69, 'end': 70},
    {'name': 'Sara', 'gender': 'female', 'start': 75, 'end': 80},
    {'name': 'George', 'gender': 'male', 'start': 84, 'end': 88},
    {'name': 'James', 'gender': 'male', 'start': 98, 'end': 101}
]

it = itemgetter("start", "end")
new_list = [d for d in input_list if it(d) not in items_to_delete]

for i in new_list:
    print(i)

# output:
# {'name': 'Sara', 'gender': 'female', 'start': 75, 'end': 80}
# {'name': 'James', 'gender': 'male', 'start': 98, 'end': 101}

您可以使用itertools.filterfalse执行类似的操作

from itertools import filterfalse

items_to_delete = [(69, 70), (84, 88)]
input_list = [
    {'name': 'John', 'gender': 'male', 'start': 69, 'end': 70},
    {'name': 'Sara', 'gender': 'female', 'start': 75, 'end': 80},
    {'name': 'George', 'gender': 'male', 'start': 84, 'end': 88},
    {'name': 'James', 'gender': 'male', 'start': 98, 'end': 101}
]

new_list = filterfalse(lambda x: (x["start"], x["end"]) in items_to_delete, input_list)

for i in new_list:
    print(i)

# output:
# {'name': 'Sara', 'gender': 'female', 'start': 75, 'end': 80}
# {'name': 'James', 'gender': 'male', 'start': 98, 'end': 101}
wnrlj8wa

wnrlj8wa2#

定义一个helper函数,它将决定是否应该保留项。

def is_viable_item(item, forbidden):
    return ((item.get("start"), item.get("end")) in forbidden) is False

filtered_input = [item for item in input_list if is_viable_item(item, items_to_delete)]

旁注:

  • 你可以跳过helper函数,把它的逻辑移到comprehension中,但是这样可读性会变差
filtered_input = [item for item in input_list if ((item.get("start"), item.get("end")) in items_to_delete) is False]
  • 你可以使用functools(partial)来冻结helper函数的第二个参数
btqmn9zl

btqmn9zl3#

错误的发生是由于内部循环。例如,当dict_ent=第一个字典元素和item=(69,70),则条件为假,并且不存储在res中。然而,在内部循环的下一次迭代中,当item的值变为(84,88),则条件满足,并且将dict存储在res中。类似地,由于内部循环的原因,第二个字典元素两次满足这个条件,所以它被存储了两次。2你可以通过扩展for循环来使用break语句来解决这个问题。

items_to_delete = [(69, 70), (84, 88)]
input_list = [{'name': 'John', 'gender': 'male', 'start': 69, 'end': 70}, 
 {'name': 'Sara', 'gender': 'female', 'start': 75, 'end': 80},  
 {'name': 'George', 'gender': 'male', 'start': 84, 'end': 88},
 {'name': 'James', 'gender': 'male', 'start': 98, 'end': 101}]
res=[]
for i in input_list:
    for j in items_to_delete:
        if i['start']==j[0] and i['end']==j[1]:
            break
    else:
        res.append(i)
for i in res:
    for j in i:
        print(j,i[j])

如果你想使用列表解析来实现这一点,你可以这样做:

items_to_delete = [(69, 70), (84, 88)]
input_list = [{'name': 'John', 'gender': 'male', 'start': 69, 'end': 70},  {'name': 'Sara', 'gender': 'female', 'start': 75, 'end': 80},   {'name': 'George', 'gender': 'male', 'start': 84, 'end': 88}, {'name': 'James', 'gender': 'male', 'start': 98, 'end': 101}]
res = [i for i in input_list if not any((i['start'], i['end']) == j for j in items_to_delete)]

for i in res:
    for j in i:
        print(j, i[j])
eyh26e7m

eyh26e7m4#

避免显式内部循环

让Python in操作符为您完成这项工作,因为它比编写内部循环更不容易出错。

input_list = [
 {'name': 'John', 'gender': 'male', 'start': 69, 'end': 70}, 
 {'name': 'Sara', 'gender': 'female', 'start': 75, 'end': 80},  
 {'name': 'George', 'gender': 'male', 'start': 84, 'end': 88},
 {'name': 'James', 'gender': 'male', 'start': 98, 'end': 101}
]

items_to_delete = [(69, 70), (84, 88)]

res = [ dict_ent for dict_ent in input_list  if (dict_ent['start'],dict_ent['end']) not in items_to_delete ]

print(res)

结果:

[
 {'name': 'Sara', 'gender': 'female', 'start': 75, 'end': 80}, 
 {'name': 'James', 'gender': 'male', 'start': 98, 'end': 101}
]

相关问题