检测python中dictionary.iteritems()的最后一次迭代
Posted
技术标签:
【中文标题】检测python中dictionary.iteritems()的最后一次迭代【英文标题】:Detect last iteration over dictionary.iteritems() in python 【发布时间】:2011-08-30 17:32:15 【问题描述】:在使用iteritems()
遍历字典时,是否有一种简单的方法可以检测最后一次迭代?
【问题讨论】:
请问为什么这很重要? Python 中的字典没有定义迭代顺序,那么最后一次迭代有什么特别之处呢? 一般来说,'somestring'.join(d.iteritems())
或 pprint
模块应该处理人们希望这样做的最常见问题
为什么不改用 OrderedDict(记住插入顺序的字典)?
@Space_C0wb0y 我正在从 dict 构造 SQL 查询的 WHERE 部分,所以从某种意义上说,这也属于@ninjagecko 建议的类别。基于 cmets,我认为最有效的方法是通过改变 dict 的字符串表示来构造 SQL 语法。
在这里找到了一个不错的解决方案.. ***.com/a/1630350/804616
【参考方案1】:
没有。使用迭代器时,您对位置一无所知 - 实际上,迭代器可能是无限的。
除此之外,字典没有排序。所以如果你需要它,例如要在元素之间插入逗号,您应该获取项目,对它们进行排序,然后它们会遍历 (key, value)
元组的列表。当迭代这个列表时,您可以轻松计算迭代次数,从而知道您何时拥有最后一个元素。
【讨论】:
【参考方案2】:有一个丑陋的方法来做到这一点:
for i, (k, v) in enumerate(your_dict.iteritems()):
if i == len(your_dict)-1:
# do special stuff here
但是你真的应该考虑是否需要这个。我几乎可以肯定还有另一种方法。
【讨论】:
假设字典不改变大小 @ninjagecko:如果是这样,那你就完蛋了。在迭代集合时调整集合的大小是一种应受惩罚的罪行,这是有原因的,它会产生高度混乱和毫无意义的结果,甚至比eval
更有用。【参考方案3】:
it = spam_dict.iteritems()
try:
eggs1 = it.next()
while True:
eggs2 = it.next()
do_something(eggs1)
eggs1 = eggs2
except StopIteration:
do_final(eggs1)
快速而且很脏。它解决了你的问题吗?
【讨论】:
-1。这在功能上等同于更简单的 for 循环:for eggs in spam_dict.iteritems(): do_something(eggs)
,然后在 for 循环之后:do_final(eggs)
。
由于更正而删除了我的 -1。但是,鉴于 Space_C0wb0y 的丑陋答案不那么丑陋且更易于理解,我不确定您为什么觉得有必要提供答案。
顺便说一句,如果字典为空,对do_final(eggs1)
的调用会引发NameError
。
好吧,我自己也不太确定。这只是一种不同的工作方式。也许不依赖长度会使其更稳定。【参考方案4】:
正如其他人所说,字典没有明确的顺序,所以很难想象你为什么需要这个,但它就是
last = None
for current in your_dict.iteritems():
if last is not None:
# process last
last = current
# now last contains the last thing in dict.iteritems()
if last is not None: # this could happen if the dict was empty
# process the last item
【讨论】:
这可以工作,但你必须做MY_NONE = object()
并使用MY_NONE
而不是None
,否则如果迭代器包含None
,这将失败
iteritems 返回 kev/value 元组,因此它不能有 None。【参考方案5】:
最有意义的方法是将循环包装在某个调用中,该调用包含一个挂钩,以便之后调用您的后迭代功能。
这可以作为上下文管理器实现并通过“with”语句调用,或者对于旧版本的 Python,您可以使用旧的“try:”...“finally:”构造。它也可以包装在一个字典迭代是自调度的类中(“私有”方法),并且附录代码遵循公共方法中的内容。 (了解公共与私有之间的差异是意图和文档的问题,而不是 Python 强制执行的)。
【讨论】:
【参考方案6】:我最近遇到了这个问题,我认为这是最优雅的解决方案,因为它允许你写for i,value,isLast in lastEnumerate(...):
:
def lastEnumerate(iterator):
x = list(iterator)
for i,value in enumerate(x):
yield i,value,i==len(x)-1
例如:
for i,value,isLast in lastEnumerate(range(5)):
print(value)
if not isLast:
print(',')
【讨论】:
【参考方案7】:这是this broader question 的一个特例。我的建议是创建一个 enumerate-like generator,它在最后一项上返回 -1:
def annotate(gen):
prev_i, prev_val = 0, gen.next()
for i, val in enumerate(gen, start=1):
yield prev_i, prev_val
prev_i, prev_val = i, val
yield '-1', prev_val
如果您希望它处理序列以及生成器,请添加 gen = iter(gen)
。
【讨论】:
【参考方案8】:for 循环中的最后一项无论如何都会在 for 循环之后挂起:
for current_item in my_dict:
do_something(current_item)
try:
do_last(current_item)
except NameError:
print "my_dict was empty"
即使在 for 循环之前使用名称“current_item”,尝试循环空字典似乎也会删除 current_item,因此出现 NameError
【讨论】:
【参考方案9】:您在上面的评论中声明您需要它来构造 SQL SELECT 语句的 WHERE 子句。也许这会有所帮助:
def make_filter(colname, value):
if isinstance(value, str):
if '%' in value:
return "%s LIKE '%s'" % (colname, value)
else:
return "%s = '%s'" % (colname, value)
return "%s = %s" % (colname, value)
filters = 'USER_ID':'123456', 'CHECK_NUM':23459, 'CHECK_STATUS':'C%'
whereclause = 'WHERE '+'\nAND '.join(make_filter(*x) for x in filters.iteritems())
print whereclause
打印出来的
WHERE CHECK_NUM = 23459
AND CHECK_STATUS LIKE 'C%'
AND USER_ID = '123456'
【讨论】:
【参考方案10】:我知道这很晚,但我是这样解决这个问题的:
dictItemCount = len(dict)
dictPosition = 1
for key,value in dict
if(dictPosition = dictItemCount):
print 'last item in dictionary'
dictPosition += 1
【讨论】:
【参考方案11】:另一种方法是枚举您的 dict 并将当前迭代与最后一个迭代进行比较。在我看来,它更容易查看和理解:
for n, (key, value) in enumerate(yourDict.items()):
if yourDict[n] == yourDict[-1]:
print('Found the last iteration!:', n)
或者你可以在迭代完成后做一些事情:
for key, value in yourDict.items():
pass
else:
print('Finished iterating over `yourDict`')
【讨论】:
您好!您能否详细说明您的解决方案为何以及如何解决您的答案中的问题?谢谢。以上是关于检测python中dictionary.iteritems()的最后一次迭代的主要内容,如果未能解决你的问题,请参考以下文章