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

我如何简化或改进它?


当前回答

你的方法没有错,除非你有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

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

其他回答

大多数情况下,让第一次迭代成为特殊情况比最后一次迭代更容易(也更便宜):

first = True
for data in data_list:
    if first:
        first = False
    else:
        between_items()

    item()

这将适用于任何迭代对象,即使是那些没有len()的迭代对象:

file = open('/path/to/file')
for line in file:
    process_line(line)

    # No way of telling if this is the last line!

除此之外,我不认为有更好的解决方案,因为这取决于你想要做什么。例如,如果您正在从列表中构建字符串,那么使用str.join()自然比使用“带有特殊情况”的For循环更好。


使用相同的原理,但更紧凑:

for i, line in enumerate(data_list):
    if i > 0:
        between_items()
    item()

看起来很眼熟,不是吗?:)


对于@ofko,以及其他真正需要找出不带len()的可迭代对象的当前值是否为最后一个值的人,你需要向前看:

def lookahead(iterable):
    """Pass through all values from the given iterable, augmented by the
    information if there are more values to come after the current one
    (True), or if it is the last value (False).
    """
    # Get an iterator and pull the first value.
    it = iter(iterable)
    last = next(it)
    # Run the iterator to exhaustion (starting from the second value).
    for val in it:
        # Report the *previous* value (more to come).
        yield last, True
        last = val
    # Report the last value.
    yield last, False

然后你可以这样使用它:

>>> for i, has_more in lookahead(range(3)):
...     print(i, has_more)
0 True
1 True
2 False

将最后一项的特殊处理延迟到循环之后。

>>> for i in (1, 2, 3):
...     pass
...
>>> i
3

迟到总比不到好。您的原始代码使用了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 i in MyList:
    # Check if 'i' is the last element in the list
    if i == MyList[-1]:
        # Do something different for the last
    else:
        # Do something for all other elements

第二个同样简单的解决方法是使用计数器:

# Count the no. of elements in the list
ListLength = len(MyList)
# Initialize a counter
count = 0

for i in MyList:
    # increment counter
    count += 1
    # Check if 'i' is the last element in the list
    # by using the counter
    if count == ListLength:
        # Do something different for the last
    else:
        # Do something for all other elements

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