【问题标题】:Itertools for containers容器的迭代工具
【发布时间】:2011-08-14 22:42:57
【问题描述】:

考虑以下交互式示例

>>> l=imap(str,xrange(1,4))
>>> list(l)
['1', '2', '3']
>>> list(l)
[]

有谁知道某处是否已经有一个带有 imap 版本(和其他 itertools 函数)的实现,以便第二次执行 list(l) 得到与第一次相同的结果。而且我不想要常规映射,因为如果您使用更大的范围,在内存中构建整个输出可能会浪费内存。

我想要一些基本上可以做类似事情的东西

class cmap:
    def __init__(self, function, *iterators):
        self._function = function
        self._iterators = iterators

    def __iter__(self):
        return itertools.imap(self._function, *self._iterators)

    def __len__(self):
        return min( map(len, self._iterators) )

但如果有人已经这样做了,那么手动为所有 itertools 执行此操作将是浪费时间。

ps。 你认为容器比迭代器更禅宗吗,因为对于像

这样的迭代器
for i in iterator:
    do something

当您明确需要删除元素的容器时,隐式清空迭代器。

【问题讨论】:

    标签: iterator python


    【解决方案1】:

    您不必为每种类型的容器构建这样的对象。基本上,你有以下几点:

    mkimap = lambda: imap(str,xrange(1,4))
    list(mkimap())
    list(mkimap())
    

    现在你需要一个漂亮的包装对象来防止“丑陋”的函数调用。这可以这样工作:

    class MultiIter(object):
        def __init__(self, f, *a, **k):
            if a or k:
                self.create = lambda: f(*a, **k)
            else: # optimize
                self.create = f
        def __iter__(self):
            return self.create()
    
    l = MultiIter(lambda: imap(str, xrange(1,4)))
    # or
    l = MultiIter(imap, str, xrange(1,4))
    # or even
    @MultiIter
    def l():
        return imap(str, xrange(1,4))
    
    # and then
    print list(l)
    print list(l)
    

    (未经测试,希望它有效,但你应该明白)

    对于您的第二个问题:迭代器和容器都有其用途。你应该选择最适合你需要的东西。

    【讨论】:

    • 我选择这个答案是因为如果您只想在不编写自己的函数或类的情况下获得此结果,我喜欢 lambda 构造。
    【解决方案2】:

    您可能正在寻找itertools.tee()

    【讨论】:

    • 这不适用于 OP。来自文档:“这个 itertool 可能需要大量辅助存储”,来自 OP:“而且我不想要常规映射,因为如果使用更大的范围,在内存中构建整个输出可能会浪费内存。”跨度>
    • 很公平,但考虑到并非所有迭代器都引用一个实际上可以连续两次是同一事物的源,他要么必须使用内存来保存它们,要么重组他的程序,以便不需要迭代器两次。
    • 也许并行化也是一件好事。我在另一个答案中的解决方案的缺点是获取下一个项目的操作必须非常便宜。如果没有,使用tee() 并并行而不是顺序进行进一步评估可能会有所帮助,以免浪费内存。
    • 我经常使用生成器编写数据处理脚本;对于调试,您可以将x = list(x) 放在步骤之间,而对于生产,您可以保留它们。这样,当您需要它时,它基本上是并行的。优化的第一步始终是确保您使用的是最佳算法(或范式)。
    【解决方案3】:

    迭代器是我最喜欢的话题;)

    from itertools import imap
    
    class imap2(object):
        def __init__(self, f, *args):
            self.g = imap(f,*args)
            self.lst = []
            self.done = False
    
        def __iter__(self):
            while True:
                try: # try to get something from g
                    x = next(self.g)
                except StopIteration:
                    if self.done:
                        # give the old values
                        for x in self.lst:
                            yield x
                    else:
                        # g was consumed for the first time
                        self.done = True
                    return
                else:
                    self.lst.append(x)
                    yield x
    
    
    
    
    l=imap2(str,xrange(1,4))
    print list(l)
    print list(l)
    

    【讨论】:

    • 这不适用于 OP:“而且我不想要常规映射,因为如果使用更大的范围,在内存中构建整个输出可能会浪费内存。”
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-05-16
    相关资源
    最近更新 更多