当使用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

我如何简化或改进它?


当前回答

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

其他回答

这是一个老问题,已经有很多很好的回答了,但我觉得这很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__,但这包括列表、元组、字典和集。

如果你正在浏览这个列表,这对我来说也是有效的:

for j in range(0, len(Array)):
    if len(Array) - j > 1:
        notLast()

迟到总比不到好。您的原始代码使用了enumerate(),但您只使用i索引来检查它是否是列表中的最后一项。下面是一个使用负索引的更简单的替代方法(如果你不需要enumerate()):

for data in data_list:
    code_that_is_done_for_every_element
    if data != data_list[-1]:
        code_that_is_done_between_elements

if data != data_list[-1]检查迭代中的当前项是否不是列表中的最后一项。

希望这能有所帮助,即使是在近11年后。

我们可以用for-else来实现

cities = [
  'Jakarta',
  'Surabaya',
  'Semarang'
]

for city in cities[:-1]:
  print(city)
else:
  print(' '.join(cities[-1].upper()))

输出:

Jakarta
Surabaya
S E M A R A N G

这个想法是我们只使用for-else循环直到n-1索引,然后在for耗尽后,我们使用[-1]直接访问最后一个索引。

谷歌让我想到了这个老问题,我想我可以用不同的方法来解决这个问题。

这里的大多数答案将处理一个正确的处理for循环控件,但如果data_list是可销毁的,我建议你从列表中弹出项目,直到你得到一个空列表:

while True:
    element = element_list.pop(0)
    do_this_for_all_elements()
    if not element:
        do_this_only_for_last_element()
        break
    do_this_for_all_elements_but_last()

如果不需要对最后一个元素做任何操作,甚至可以使用while len(element_list)。我发现这个解决方案比处理next()更优雅。