对每个满足的条件执行块,否则执行其他块

Perform block for each satisfied condition, otherwise perform other block

想象一下,您必须 select 一些值,并且对于每个值,您都必须评估一个块。另一方面,如果没有满足条件的值,则必须评估另一个块。

示例: 考虑下一个方法签名:

forPositivesOf: aCollection do: aBlock otherwise: defaultBlock

此方法应使用 aCollection 的每个正元素评估块 aBlock,但如果没有这样的元素,则评估 defaultBlock。请注意,实际上该方法可能会计算出比正数更复杂的东西,并且可以有一个更复杂的对象而不是 aCollection。

目前我看到两种解决方案:

1)

forPositivesOf: aCollection do: aBlock otherwise: defaultBlock
  (aCollection select: #positive)
    ifEmpty: [ defaultBlock value ]
    ifNotEmpty: [ :collection |
      collection do: [ :el | aBlock cull: el ] ]

但如果 positive 的计算成本很高,那么最好为第一个遇到的元素计算 aBlock,因为通过 aBlock 的人将能够做出反应以任何想要的方式。

2)

forPositivesOf: aCollection do: aBlock otherwise: defaultBlock
  | encountered |
  encountered := false.
  aCollection do: [ :el |
    el positive ifTrue: [
      encountered := true.
      aBlock cull: el ] ].

  encountered ifFalse: [
    defaultBlock value ]

但我不喜欢额外遇到的变量,它使代码的功能性降低。

第一个替代方案的更紧凑版本如下,它不实例化新的闭包,只使用接收到的闭包作为参数。

forPositivesOf: aCollection do: aBlock otherwise: defaultBlock

    ^(aCollection select: [:each | each positive ]) 
         ifEmpty: defaultBlock
         ifNotEmpty: [ :collection | collection do: aBlock ]

一种适用于 SequenceableCollections 的非常好的功能方式:

forPositivesOf: aCollection do: aBlock otherwise: defaultBlock
  (aCollection
    select: #positive
    thenCollect: [ :el | aBlock cull: el ]) ifEmpty: [ defaultBlock value ]

进一步研究 Uko 的解决方案:

forPositivesOf: aCollection do: aBlock otherwise: defaultBlock
    ^ (aCollection
          select: #positive
          thenCollect: aBlock
      ) ifEmpty: defaultBlock