当使用for循环迭代时,我如何处理输入的最后一个元素?特别是,如果有代码应该只出现在元素之间(而不是在最后一个元素之后),我该如何构造代码?

目前,我写的代码是这样的:

for i, data in enumerate(data_list):
    code_that_is_done_for_every_element
    if i != len(data_list) - 1:
        code_that_is_done_between_elements

我如何简化或改进它?


当前回答

我喜欢@ethan-t的方法,但从我的角度来看,True是危险的。

data_list = [1, 2, 3, 2, 1]  # sample data
L = list(data_list)  # destroy L instead of data_list
while L:
    e = L.pop(0)
    if L:
        print(f'process element {e}')
    else:
        print(f'process last element {e}')
del L

这里,data_list的值是,最后一个元素的值等于列表的第一个元素。L可以与data_list交换,但在这种情况下,循环后它的结果为空。如果你在处理前检查该列表不为空或检查不需要(哎呀!),也可以使用True。

data_list = [1, 2, 3, 2, 1]
if data_list:
    while True:
        e = data_list.pop(0)
        if data_list:
            print(f'process element {e}')
        else:
            print(f'process last element {e}')
            break
else:
    print('list is empty')

好处是它很快。坏的-它是可销毁的(data_list变成空)。

最直观的解决方案:

data_list = [1, 2, 3, 2, 1]  # sample data
for i, e in enumerate(data_list):
    if i != len(data_list) - 1:
        print(f'process element {e}')
    else:
        print(f'process last element {e}')

哦,是的,你已经提出来了!

其他回答

是否不可能遍历除最后一个元素以外的所有元素,并在循环之外处理最后一个元素?毕竟,创建循环的目的与循环遍历的所有元素类似;如果一个元素需要一些特殊的东西,它就不应该在循环中。

(另请参阅这个问题:循环中的最后一个元素是否值得单独处理)

编辑:因为这个问题更多的是关于“中间”,所以要么第一个元素是特殊的,因为它没有前一个元素,要么最后一个元素是特殊的,因为它没有后继元素。

您可以在输入数据上使用滑动窗口来查看下一个值,并使用哨兵来检测最后一个值。这适用于任何可迭代对象,所以你不需要事先知道它的长度。成对实现来自itertools recipes。

from itertools import tee, izip, chain

def pairwise(seq):
    a,b = tee(seq)
    next(b, None)
    return izip(a,b)

def annotated_last(seq):
    """Returns an iterable of pairs of input item and a boolean that show if
    the current item is the last item in the sequence."""
    MISSING = object()
    for current_item, next_item in pairwise(chain(seq, [MISSING])):
        yield current_item, next_item is MISSING:

for item, is_last_item in annotated_last(data_list):
    if is_last_item:
        # current item is the last item

我在下面分享了两个简单的方法来查找循环的结束。

方法1:

num_list = [1, 2, 3, 4]

for n in num_list:
    if num_list[-1] == n:
        print('this is the last iteration of the loop')

方法2:

num_list = [1, 2, 3, 4]

loop_count = len(num_list) - 1  # 3
for index, num in enumerate(num_list):
    if index == loop_count:
        print('this is the last iteration of the loop')

因此,这绝对不是“更短”的版本——如果“最短”和“Pythonic”实际上是兼容的,人们可能会离题。

但如果经常需要这种模式,就把逻辑放到a中 10行生成器-并获得与元素相关的任何元数据 在for调用中直接定位。这里的另一个优势是它会 适用于任意可迭代对象,而不仅仅是序列。

_sentinel = object()

def iter_check_last(iterable):
    iterable = iter(iterable)
    current_element = next(iterable, _sentinel)
    while current_element is not _sentinel:
        next_element = next(iterable, _sentinel)
        yield (next_element is _sentinel, current_element)
        current_element = next_element
In [107]: for is_last, el in iter_check_last(range(3)):
     ...:     print(is_last, el)
     ...: 
     ...: 
False 0
False 1
True 2

这是一个老问题,已经有很多很好的回答了,但我觉得这很python:

def rev_enumerate(lst):
    """
    Similar to enumerate(), but counts DOWN to the last element being the
    zeroth, rather than counting UP from the first element being the zeroth.

    Since the length has to be determined up-front, this is not suitable for
    open-ended iterators.

    Parameters
    ----------
    lst : Iterable
        An iterable with a length (list, tuple, dict, set).

    Yields
    ------
    tuple
        A tuple with the reverse cardinal number of the element, followed by
        the element of the iterable.
    """
    length = len(lst) - 1
    for i, element in enumerate(lst):
        yield length - i, element

这样用:

for num_remaining, item in rev_enumerate(['a', 'b', 'c']):
    if not num_remaining:
        print(f'This is the last item in the list: {item}')

或者你想做相反的事情:

for num_remaining, item in rev_enumerate(['a', 'b', 'c']):
    if num_remaining:
        print(f'This is NOT the last item in the list: {item}')

或者,只是想知道当你走的时候还剩下多少……

for num_remaining, item in rev_enumerate(['a', 'b', 'c']):
    print(f'After {item}, there are {num_remaining} items.')

我认为现有枚举的通用性和熟悉性使其最具python性。

注意,与enumerate()不同,rev_enumerate()要求输入实现__len__,但这包括列表、元组、字典和集。