使用Pharo,我有一个集合,例如
array := #('up' '4' 'b').
和我想使用select:
创建一个集合,只包括数字,前提是它们小于20,和一个特定的字符串-在这种情况下,'up'和'4'
我试着:
array select: [:each | (each='up') | (each asInteger < 50)].
这导致MessageNotUnderstood
,因为receiver of "<" is nil
。
我想我必须创建一个局部变量x:= each asInteger
,但就是无法解决。
你得到一个MessageNotUnderstood
,因为你的代码正试图测试是否'b' asInteger
(这是nil
,因为b
不是一个整数)是< 20
(或< 50
;你的文本和代码中有不同的数字)。因此,您所需要做的就是在将每个数组项视为数字之前测试它是否为数字。
这应该在Pharo工作区中工作:
| array |
array := #('up' '4' 'b' '22').
^array select: [ :each | each = 'up'
or: [ each isAllDigits and: [ each asInteger < 20 ] ] ]
检查此结果将得到#('up' '4')
。
请注意,我正在检查每个字符串是否"由所有数字组成",并且只有在这种情况下才进行比较。还请注意,我使用的是or:
和and:
,它们只在需要时计算block参数,而|
和&
无论如何都计算两边。
你也可以创建一个局部变量,正如你说你尝试过的,但它看起来有点笨拙(我不会叫变量x
…除非是x坐标):
| array |
array := #('up' '4' 'b' '22').
^array select: [ :each |
each = 'up' or: [
| integerOrNil |
integerOrNil := each asInteger.
integerOrNil notNil and: [ integerOrNil < 20 ] ] ]
使用select:
,您一次只能访问数组的一个元素。从你的代码我看到你想访问数组的两个元素在同一时间。您可以在本例中使用pairsDo:
。例如,下面的代码将字符串'up'前面的所有数字放入数组中。
numbers := OrderedCollection new.
#('up' '5' 'b') pairsDo: [ :first :second |
((first = 'up') and: [ second asInteger notNil ])
ifTrue: [ numbers add: second asInteger ] ]
你可以使用select:
只获取那些小于20的数字:
numbers select: [:each| each < 20].
你会得到这个错误,因为第二个比较语句总是被执行:在pharo(和任何smalltalk)中的消息|不作为同音C操作符,而是始终被执行,而不管语句第一部分的结果如何(&也一样,btw)。
为了获得类似的结果,您似乎假装(仅在第一个子句为真时执行or子句),我们使用消息或:和和:你可以这样做:
array select: [ :each |
each = 'up'
or: [ each = '4'
or: [ each isAllDigits and: [ each asInteger < 20 ] ] ] ]
请注意调用#或:语句的嵌套,以及我首先检查数字是否可以转换为数字的事实。如果我不这样做,当我尝试将字符串转换为数字时,我会得到nil,因为解析(转换)字符串转换为数字失败(然后选择将失败)。
另一种可能的方法是:
array select: [ :each |
each = 'up'
or: [ each = '4'
or: [ each asInteger notNil and: [ each asInteger < 20 ] ] ] ]
但我推荐第一个(使用解析器的失败来确定字符串是否包含数字的方法很容易被认为是一个漏洞:)
最后,如果你必须选择一个或两个以上的"常量"字符串,你可以这样做:
constants := #('up' '4').
array select: [ :each |
(constants includes: each)
or: [ each asInteger notNil and: [ each asInteger < 20 ] ] ]
可能是一个更干净的实现