如何从序列的特定点迭代(Python)
[编辑]
根据我收到的反馈和回答,我发现大家对最初的问题有些困惑。因此,我把问题简化到了最基本的形式。
以下是问题的相关事实:
- 我有一个已经排好序的序列:S
- 我有一个项目(用i表示),这个项目肯定在S里面
- 我想要一个find()算法,它能返回一个迭代器(iter),这个迭代器指向i
- 在得到这个迭代器后,我希望能够从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]
>>>