以迭代方式跳过元素的优雅方式

发布于 2021-01-29 14:10:39

我有一个大的可迭代项,实际上,由以下给定:

itertools.permutations(range(10))

我想访问百万分之一的元素。我确实以不同的方式解决了问题。

  1. 强制迭代到列表并获取第1000000个元素:

    return list(permutations(range(10)))[999999]
    
  2. 手动跳过直到999999的元素:

    p = permutations(range(10))
    

    for i in xrange(999999): p.next()
    return p.next()

  3. 手动跳过元素v2:

    p = permutations(range(10))
    

    for i, element in enumerate(p):
    if i == 999999:
    return element

  4. 使用itertools中的islice:

    return islice(permutations(range(10)), 999999, 1000000).next()
    

但是我仍然觉得,没有一个是python做到这一点的优雅方法。第一种选择太昂贵了,它只需要访问一个元素就需要计算整个可迭代项。如果我没有记错的话,islice在内部执行的方法与方法2相同,几乎与第3种完全相同,也许它具有更多的冗余操作。

因此,我很好奇,想知道python中是否存在其他某种方式来访问可迭代的具体元素,或者至少以某种更为优雅的方式跳过了第一个元素,或者我是否只需要使用一个以上。

关注者
0
被浏览
130
1 个回答
  • 面试哥
    面试哥 2021-01-29
    为面试而生,有面试问题,就找面试哥。

    使用itertools配方consume跳过n元素:

    def consume(iterator, n):
        "Advance the iterator n-steps ahead. If n is none, consume entirely."
        # Use functions that consume iterators at C speed.
        if n is None:
            # feed the entire iterator into a zero-length deque
            collections.deque(iterator, maxlen=0)
        else:
            # advance to the empty slice starting at position n
            next(islice(iterator, n, n), None)
    

    注意islice()那里的电话;它使用n, n,实际上不返回 任何内容 ,并且该next()函数返回到默认值。

    简化为示例,您要跳过999999个元素,然后返回元素1000000:

    return next(islice(permutations(range(10)), 999999, 1000000))
    

    islice() 处理C语言中的迭代器,Python循环无法胜任。

    为了说明这一点,以下是每种方法仅重复10次的时间:

    >>> from itertools import islice, permutations
    >>> from timeit import timeit
    >>> def list_index():
    ...     return list(permutations(range(10)))[999999]
    ... 
    >>> def for_loop():
    ...     p = permutations(range(10))
    ...     for i in xrange(999999): p.next()
    ...     return p.next()
    ... 
    >>> def enumerate_loop():
    ...     p = permutations(range(10))
    ...     for i, element in enumerate(p):
    ...         if i == 999999:
    ...             return element
    ... 
    >>> def islice_next():
    ...     return next(islice(permutations(range(10)), 999999, 1000000))
    ... 
    >>> timeit('f()', 'from __main__ import list_index as f', number=10)
    5.550895929336548
    >>> timeit('f()', 'from __main__ import for_loop as f', number=10)
    1.6166789531707764
    >>> timeit('f()', 'from __main__ import enumerate_loop as f', number=10)
    1.2498459815979004
    >>> timeit('f()', 'from __main__ import islice_next as f', number=10)
    0.18969106674194336
    

    islice()方法比下一个最快的方法快近7倍。



知识点
面圈网VIP题库

面圈网VIP题库全新上线,海量真题题库资源。 90大类考试,超10万份考试真题开放下载啦

去下载看看