搜索并从元组列表中移除
我有一个待办事项列表,里面的内容是用元组的形式表示的...
[(datetime.datetime(2014, 2, 28, 0, 0), '教程登录'), (datetime.datetime(2014, 4, 9, 0, 0), '作业 1'), (datetime.datetime(2014, 4, 22, 0, 0), '作业 2'), (datetime.datetime(2014, 6, 14, 0, 0), '考试复习'), (datetime.datetime(2014, 3, 15, 0, 0), '买杂货'), (datetime.datetime(2014, 3, 20, 0, 0), '洗衣服'), (datetime.datetime(2014, 3, 26, 0, 0), '数学作业'), (datetime.datetime(2014, 3, 31, 0, 0), '写待办事项列表'), (datetime.datetime(2014, 4, 4, 0, 0), '申请工作'), (datetime.datetime(2014, 4, 14, 0, 0), '拖延'), (datetime.datetime(2014, 4, 19, 0, 0), '买复活节彩蛋'), (datetime.datetime(2014, 4, 25, 0, 0), '买安扎克饼干')]
我正在尝试写一个函数,如果待办事项的名称和列表中的某个任务匹配,就把这个元组从列表中删除。如果没有找到匹配的名称,函数会返回 False。目前我写的代码总是返回 False,即使这个任务确实存在。
def remove_item(todolist, name):
for t in todolist:
if t[1] is name:
del t
else:
return False
3 个回答
你的代码有几个问题:
- 你用了
is
这个操作符,它是用来比较对象的“身份”的。你应该用==
来比较它们的值,这样才能得到你想要的结果。 - 在循环中删除一个项目会搞乱迭代器。正确的做法是先记录下要删除的项目的索引,然后在循环外面删除它。更好的选择是用
filter
函数来过滤列表,或者使用列表推导式来生成一个新的列表。 - 你的
return False
语句缩进不对。它应该在for
循环外面。
我会这样写代码:
def remove_item(todo_list, item):
return filter(lambda x: x[1] != item, todo_list)
在遍历一个列表的时候删除其中的某个项是个坏主意,因为这样会搞乱列表的迭代器,导致你跳过每个被删除项后面的那个项。如果你有两个要删除的项,一个接一个地删除,那你就麻烦了。
不过,有三种方法可以解决这个问题:
反向遍历列表(虽然有点麻烦,但有效)。
使用列表推导式——创建一个新列表,省略掉那些要“删除”的值。这种方法通常最容易阅读。
遍历列表并记录下要删除的项的索引,然后再根据这些索引去删除(比如,删除第i项时要减去已经删除的项的数量),也就是要考虑到列表变小了。这种方法也有点麻烦。
第二种方法的代码大概是这样的:
def remove_item(todolist, name):
result = [item for item in todolist if name != item[1]]
if len(todolist) == len(result):
return False # nothing removed
else:
return result
你代码的问题在于,你使用的是引用相等(也就是用'is'
这个操作符),而不是值相等(用'=='
这个操作符)。
举个例子:
>>> a = 'tutorial signons'
>>> b = 'tutorial signons'
a is b
会返回False
,但是a == b
会返回True
。
想了解更多,可以查看这个链接。
所以,你可以这样做,应该能达到你想要的效果:
def remove_item(todo_list, name):
for t in todolist:
if t[1] == name:
del t
else:
return False
不过,从你正在遍历的列表中删除元素并不是个好主意。你可能想创建一个新列表,或者使用类似这样的方式:
filtered_list = filter(lambda x: x[1] != 'some_string', todo_list)
这样会把列表中所有匹配some_string
的元组都移除。