有没有像"iterate iterable if it has elements, else ..."这样的结构?

Is there a construct like "iterate iterable if it has elements, else ..."?

是否有更紧凑的方法来迭代具有元素的可迭代对象,或者如果没有元素则执行其他操作?

我的"problem"在Python,但我也对其他语言感兴趣。

目前我先测试元素个数:

In [1]: l=[]

In [2]: if l:
   ...:     for e in l:
   ...:         print(e)
   ...: else:
   ...:     print("else")
   ...:
else

for statement has an else:

In [2]: for e in []:
   ...:     print(e)
   ...: else:
   ...:     print("else")
   ...:
else

但是它的"suite"(块)也在迭代完成时执行:

In [1]: for e in [1,2,3]:
   ...:     print(e)
   ...: else:
   ...:     print("else")
   ...:
1
2
3
else

我意识到这里没有太多收获(一行和缩进级别),但我很好奇是否存在这样的东西。

大多数时候你只是测试长度并提前退出:

if not l:
    # empty case
    return  # or raise exception

无论如何,因为迭代不会在空列表上发生,下面的也足够了,不需要else

if not l:
    # empty case
for i in l:
    # only ever executed if there are any elements

for ... else 套件仅对提前退出 的循环有用; else 套件针对 完成 的所有循环执行。如果使用 break,则跳过 else。这使得它不适合检测空序列,因为在没有 break 语句的情况下,无论元素数量如何,对这些序列的迭代都会成功完成。

既然你要求其他语言,这里是Squeak/Pharo Smalltalk,因为范式足够接近Python:

你会这样写:

aCollection
    ifEmpty: [Transcript cr; show: 'else']
    ifNotEmpty: [aCollection do: [:each | Transcript cr; show: each printString]].

您也可以在 Collection 中创建一个新方法:

ifNotEmptyDo: aBlock elseDo: elseBlock
    self isEmpty ifTrue: [^elseBlock value].
    ^self do: aBlock

然后像这样使用它:

aCollection
    ifNotEmptyDo: [:each | Transcript cr; show: each printString]
    elseDo: [Transcript cr; show: 'else'].

注意 isEmpty 默认定义为 ^self size = 0,这对于可能的惰性或无限集合来说是一种异端……所以我提出这个新定义:

isEmpty
    self do: [:each |^false].
    ^true

只是为了看看测试空性或执行循环或多或少是相同的任务;)

结论,在Smalltalk中语法糖的水平很低
块闭包启用不同的、有条件的或重复的评估。
因此,所有的构造,如分支和循环以及它们的组合,都只是以块闭包为参数的普通消息,您可以随意添加自己的构造。
这个设施经常被过度选择器滥用,以获得非常小的附加值,因此对新构造的需求应该始终与维护成本保持平衡(更多的方法来实施、测试和为新手学习等......) .让我们记住:“小即是美”。