搜索并从元组列表中移除

1 投票
3 回答
1884 浏览
提问于 2025-04-18 01:06

我有一个待办事项列表,里面的内容是用元组的形式表示的...

[(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 个回答

0

你的代码有几个问题:

  1. 你用了 is 这个操作符,它是用来比较对象的“身份”的。你应该用 == 来比较它们的值,这样才能得到你想要的结果。
  2. 在循环中删除一个项目会搞乱迭代器。正确的做法是先记录下要删除的项目的索引,然后在循环外面删除它。更好的选择是用 filter 函数来过滤列表,或者使用列表推导式来生成一个新的列表。
  3. 你的 return False 语句缩进不对。它应该在 for 循环外面。

我会这样写代码:

def remove_item(todo_list, item):
    return filter(lambda x: x[1] != item, todo_list)
1

在遍历一个列表的时候删除其中的某个项是个坏主意,因为这样会搞乱列表的迭代器,导致你跳过每个被删除项后面的那个项。如果你有两个要删除的项,一个接一个地删除,那你就麻烦了。

不过,有三种方法可以解决这个问题:

  1. 反向遍历列表(虽然有点麻烦,但有效)。

  2. 使用列表推导式——创建一个新列表,省略掉那些要“删除”的值。这种方法通常最容易阅读。

  3. 遍历列表并记录下要删除的项的索引,然后再根据这些索引去删除(比如,删除第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
2

你代码的问题在于,你使用的是引用相等(也就是用'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的元组都移除。

撰写回答