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

其他回答

这类似于Ants Aasma的方法,但没有使用itertools模块。它也是一个滞后迭代器,它可以提前查找迭代器流中的单个元素:

def last_iter(it):
    # Ensure it's an iterator and get the first field
    it = iter(it)
    prev = next(it)
    for item in it:
        # Lag by one item so I know I'm not at the end
        yield 0, prev
        prev = item
    # Last item
    yield 1, prev

def test(data):
    result = list(last_iter(data))
    if not result:
        return
    if len(result) > 1:
        assert set(x[0] for x in result[:-1]) == set([0]), result
    assert result[-1][0] == 1

test([])
test([1])
test([1, 2])
test(range(5))
test(xrange(4))

for is_last, item in last_iter("Hi!"):
    print is_last, item

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

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

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

我们可以用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]直接访问最后一个索引。

你的方法没有错,除非你有10万个循环,想要保存10万个“if”语句。在这种情况下,你可以这样做:

iterable = [1,2,3] # Your date
iterator = iter(iterable) # get the data iterator

try :   # wrap all in a try / except
    while 1 : 
        item = iterator.next() 
        print item # put the "for loop" code here
except StopIteration, e : # make the process on the last element here
    print item

输出:

1
2
3
3

但说真的,在你的情况下,我觉得这太过分了。

在任何情况下,你可能会更幸运的切片:

for item in iterable[:-1] :
    print item
print "last :", iterable[-1]

#outputs
1
2
last : 3

或者只是:

for item in iterable :
    print item
print iterable[-1]

#outputs
1
2
3
last : 3

最终,一个KISS的方式来做你的事情,这将适用于任何迭代对象,包括那些没有__len__的迭代对象:

item = ''
for item in iterable :
    print item
print item

Ouputs:

1
2
3
3

如果我这样做的话,对我来说很简单。

如果项目是唯一的:

for x in list:
    #code
    if x == list[-1]:
        #code

其他选项:

pos = -1
for x in list:
    pos += 1
    #code
    if pos == len(list) - 1:
        #code


for x in list:
    #code
#code - e.g. print x


if len(list) > 0:
    for x in list[:-1]:
        #process everything except the last element
    for x in list[-1:]:
        #process only last element