如何从序列的特定点迭代(Python)

2 投票
6 回答
751 浏览
提问于 2025-04-16 05:59

[编辑]

根据我收到的反馈和回答,我发现大家对最初的问题有些困惑。因此,我把问题简化到了最基本的形式。

以下是问题的相关事实:

  1. 我有一个已经排好序的序列:S
  2. 我有一个项目(用i表示),这个项目肯定在S里面
  3. 我想要一个find()算法,它能返回一个迭代器(iter),这个迭代器指向i
  4. 在得到这个迭代器后,我希望能够从i开始(包括i)向前(或者向后?)遍历S中的元素

对于那些会用C++编程的朋友们,如果你们也会用Python,我想要的就是相当于:

const_iterator std::find (const key_type& x ) const;

返回的迭代器可以用来遍历这个序列。我只是想找找看,Python里面有没有类似的内置算法,这样就不用我自己重新发明轮子了。

6 个回答

1

是的,你可以这样做:

import itertools
from datetime import datetime

data = {
      "2008-11-10 17:53:59":"data",
      "2005-11-10 17:53:59":"data",
}

list_ = data.keys()
new_list = [datetime.strptime(x, "%Y-%m-%d %H:%M:%S") for x in list_]

begin_date = datetime.strptime("2007-11-10 17:53:59", "%Y-%m-%d %H:%M:%S")

for i in itertools.ifilter(lambda x: x > begin_date, new_list):
    print i
1

如果你确定你的序列里的项目是排好序的,你可以直接使用生成器表达式:

(item for item in seq if item >= 5)

这个会返回一个生成器;它实际上并不会遍历列表,直到你开始迭代它,也就是说:

for item in (item for item in seq if item > 5)
    print item

只会遍历一次 seq

像这样使用生成器表达式和使用 itertools.ifilter 基本是一样的,后者会生成一个生成器,遍历列表并只返回符合过滤条件的值:

>>> import itertools
>>> seq = [1, 2, 3, 4, 5, 6, 7]
>>> list(itertools.ifilter(lambda x: x>=3, seq))
[3, 4, 5, 6, 7]

我不太明白为什么(除了向后兼容)现在有了生成器表达式后,我们还需要 itertools.ifilter,不过 itertools 中的其他方法是非常有用的。

比如说,如果你不知道你的序列是否是排好序的,但你仍然想从一个已知的项目开始返回序列中的所有内容,你就不能使用生成器表达式。相反,你应该使用 itertools.dropwhile。这个会生成一个生成器,遍历列表并跳过值,直到找到一个符合过滤条件的值:

>>> seq = [1, 2, 4, 3, 5, 6, 7]
>>> list(itertools.dropwhile(lambda x: x != 3, seq))
[3, 5, 6, 7]

至于向后搜索,这只在你使用的序列实际上是一个序列(比如列表,也就是有一个结束并且可以向后导航的东西)时才有效,而不是任何可迭代的对象(例如,返回下一个质数的生成器)。要做到这一点,可以使用 reversed 函数,例如:

(item for item in reversed(seq) if item >= 5)
1

根据你提供的相关信息:

>>> import bisect
>>> def find_fwd_iter(S, i):
...     j = bisect.bisect_left(S, i)
...     for k in xrange(j, len(S)):
...         yield S[k]
...
>>> def find_bkwd_iter(S, i):
...     j = bisect.bisect_left(S, i)
...     for k in xrange(j, -1, -1):
...         yield S[k]
...
>>> L = [100, 150, 200, 300, 400]
>>> list(find_fwd_iter(L, 200))
[200, 300, 400]
>>> list(find_bkwd_iter(L, 200))
[200, 150, 100]
>>>

撰写回答