Using Pharo, I have a collection e.g.
array := #('up' '4' 'b').
and I'd like to use select:
to create a collection that only includes the numbers, provided they're smaller than 20, and a specific string - in this case, 'up' and '4'
I tried:
array select: [:each | (each='up') | (each asInteger < 50)].
This leads to a MessageNotUnderstood
because receiver of "<" is nil
.
I figured I'd have to create a local variable x:= each asInteger
, but just couldn't work it out.
You're getting a MessageNotUnderstood
because your code is trying to test whether 'b' asInteger
(which is nil
, because b
isn't an integer) is < 20
(or < 50
; you have different numbers in your text and your code). So all you need to do is test whether each array item is a number before you treat it as such.
This should work in a Pharo workspace:
| array |
array := #('up' '4' 'b' '22').
^array select: [ :each | each = 'up'
or: [ each isAllDigits and: [ each asInteger < 20 ] ] ]
Inspecting the result of this gives #('up' '4')
as expected.
Note that I'm checking whether each string is "made up of all digits", and only doing the comparison if that is the case. Also note that I'm using or:
and and:
, which only evaluate the block argument if required, while |
and &
evaluate both sides regardless.
You could also create a local variable, as you said you tried, but it would look a little clunkier (and I wouldn't call the variable x
... unless it's an x-coordinate):
| array |
array := #('up' '4' 'b' '22').
^array select: [ :each |
each = 'up' or: [
| integerOrNil |
integerOrNil := each asInteger.
integerOrNil notNil and: [ integerOrNil < 20 ] ] ]