e.t*_*deu 166 python for-loop idioms fencepost
我想知道对for循环中的最后一个元素进行特殊处理的最佳方法(更紧凑和"pythonic"方式).有一段代码只能在元素之间调用,在最后一个元素中被抑制.
以下是我目前的工作方式:
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
Run Code Online (Sandbox Code Playgroud)
有没有更好的方法?
注意:我不想使用hacks,例如使用reduce;)
Fer*_*yer 133
大多数情况下,将第一次迭代变为特殊情况而不是最后一次迭代更容易(也更便宜):
first = True
for data in data_list:
if first:
first = False
else:
between_items()
item()
Run Code Online (Sandbox Code Playgroud)
这适用于任何迭代,即使对于那些没有len():
file = open('/path/to/file')
for line in file:
process_line(line)
# No way of telling if this is the last line!
Run Code Online (Sandbox Code Playgroud)
除此之外,我认为没有一个普遍优越的解决方案,因为它取决于你想要做什么.例如,如果您从列表中建立一个字符串,它是自然最好使用str.join()比使用for循环"特殊情况".
使用相同的原则,但更紧凑:
for i, line in enumerate(data_list):
if i > 0:
between_items()
item()
Run Code Online (Sandbox Code Playgroud)
看起来很熟悉,不是吗?:)
对于@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
Run Code Online (Sandbox Code Playgroud)
然后你可以像这样使用它:
>>> for i, has_more in lookahead(range(3)):
... print(i, has_more)
0 True
1 True
2 False
Run Code Online (Sandbox Code Playgroud)
S.L*_*ott 18
'代码之间'是头尾模式的一个例子.
你有一个项目,后面是一系列(之间,项目)对.您还可以将其视为一系列(项目,之间)对,后跟项目.将第一个元素作为特殊元素并将所有其他元素作为"标准"案例通常更简单.
此外,为避免重复代码,您必须提供一个函数或其他对象来包含您不想重复的代码.在一个循环中嵌入一个if语句,除了一次之外总是假的,这有点愚蠢.
def item_processing( item ):
# *the common processing*
head_tail_iter = iter( someSequence )
head = head_tail_iter.next()
item_processing( head )
for item in head_tail_iter:
# *the between processing*
item_processing( item )
Run Code Online (Sandbox Code Playgroud)
这更可靠,因为它更容易证明,它不会创建额外的数据结构(即列表的副本),并且不需要大量浪费执行if条件,除了一次之外总是假的.
Bar*_*tek 15
如果您只是想修改最后一个元素,data_list那么您只需使用符号:
L[-1]
Run Code Online (Sandbox Code Playgroud)
但是,看起来你做的不止于此.你的方式没有什么不妥.我甚至快速浏览了一些Django代码来获取模板标签,它们基本上就是你正在做的事情.
Nur*_*uda 14
我们可以使用for-else
cities = [
'Jakarta',
'Surabaya',
'Semarang'
]
for city in cities[:-1]:
print(city)
else:
print(' '.join(cities[-1].upper()))
Run Code Online (Sandbox Code Playgroud)
输出:
Jakarta
Surabaya
S E M A R A N G
Run Code Online (Sandbox Code Playgroud)
这个想法是我们只使用for-else循环直到n-1索引,然后在for耗尽之后,我们使用直接访问最后一个索引[-1]。
小智 13
虽然这个问题很老,但我是通过谷歌来到这里的,我找到了一个非常简单的方法:列表切片.假设您想在所有列表条目之间加上"&".
s = ""
l = [1, 2, 3]
for i in l[:-1]:
s = s + str(i) + ' & '
s = s + str(l[-1])
Run Code Online (Sandbox Code Playgroud)
这将返回'1&2&3'.
And*_*lke 10
这类似于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
Run Code Online (Sandbox Code Playgroud)
如果项目是唯一的:
for x in list:
#code
if x == list[-1]:
#code
Run Code Online (Sandbox Code Playgroud)
其他选择:
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]
#code
for x in list[-1]:
#code
Run Code Online (Sandbox Code Playgroud)
您可以使用此代码确定最后一个元素:
for i,element in enumerate(list):
if (i==len(list)-1):
print("last element is" + element)
Run Code Online (Sandbox Code Playgroud)
您可以在输入数据上使用滑动窗口来查看下一个值,并使用标记来检测最后一个值。这适用于任何可迭代对象,因此您无需事先知道长度。成对实现来自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
Run Code Online (Sandbox Code Playgroud)
我将提供一种更优雅、更健壮的方式,如下所示,使用拆包:
def mark_last(iterable):
try:
*init, last = iterable
except ValueError: # if iterable is empty
return
for e in init:
yield e, True
yield last, False
Run Code Online (Sandbox Code Playgroud)
测试:
for a, b in mark_last([1, 2, 3]):
print(a, b)
Run Code Online (Sandbox Code Playgroud)
结果是:
1 对
2 对
3 错
| 归档时间: |
|
| 查看次数: |
148291 次 |
| 最近记录: |