SequenceableCollection >> splitOnFirst: is a valuable and missing method
In microdown we define
Sequenceable >> splitOnFirst: anObject
"Split the receiver on the first element that match anObject"
"#(1 2 3 0 4 5 6 0 7) splitOnFirst: 0 >> #(#(1 2 3) #(4 5 6 0 7)) "
| indexOfElement |
indexOfElement := self indexOf: anObject.
indexOfElement = 0 ifTrue: [ ^ { self. #() } ].
^ { self copyFrom: 1 to: indexOfElement -1 . self copyFrom: indexOfElement + 1 to: self size }
And we believe that this method deserves to be in Pharo because it is really useful. This deserves more tests.
We can imagine also another one
Sequenceable >> splitOnFirstSatisfy: aPrediate
"Split the receiver on the first element that satisfy aPrediate"
"#(1 2 3 0 4 5 6 0 7) splitOnFirst: [:each | each isZero]) >> #(#(1 2 3) #(4 5 6 0 7)) "
the following is better than the first one. It lets clients adjust their semantics.
splitOnFirst: anObject noneValue: aValue
"Split the receiver on the first element that match anObject"
"#(1 2 3 0 4 5 6 0 7) splitOnFirst: 0 noneValue: 33 >> #(#(1 2 3) #(4 5 6 0 7)) "
"#(1 2 3 0 4 5 6 0 7) splitOnFirst: 99 nonValue: nil >> #(#(1 2 3 04 5 6 0 7) nil "
| element |
element := self indexOf: anObject.
element = 0 ifTrue: [ ^ { self. aValue } ].
^ { self copyFrom: 1 to: element -1 . self copyFrom: element + 1 to: self size }
splitOnFirst: anObject
"Split the receiver on the first element that match anObject, returns two sequenceable."
"#(1 2 3 0 4 5 6 0 7) splitOnFirst: 0 >> #(#(1 2 3) #(4 5 6 0 7)) "
"#(1 2 3 0 4 5 6 0 7) splitOnFirst: 99 >> #(#(1 2 3 04 5 6 0 7) #() "
^ self splitOnFirst: anObject noneValue: #()
Would it be more idiomatic to use #splitOnFirst:ifNone: like #detect:ifNone:
The slight difference might be that the ifNone: would be aBlock meaning you could either handle the error or choose to return the collection.
Good idea. I have to think about because with ifNone: how do I return #(#(1 2 3 04 5 6 0 7) #())
#(1 2 3 0 4 5 6 0 7) splitOnFirst: 99 ifNone: [ :orginalCollection ]
splitOnFirst: anObject ifNone: aOneValueBlock
"Split the receiver on the first element that match anObject"
"#(1 2 3 0 4 5 6 0 7) splitOnFirst: 0 noneValue: 33 >> #(#(1 2 3) #(4 5 6 0 7)) "
"#(1 2 3 0 4 5 6 0 7) splitOnFirst: 99 nonValue: nil >> #(#(1 2 3 04 5 6 0 7) nil "
| element |
element := self indexOf: anObject.
element = 0 ifTrue: [ ^ aBloc value: { self. aValue } ].
^ { self copyFrom: 1 to: element -1 . self copyFrom: element + 1 to: self size }
But this is not the same as ifNone: because ifNone: does not need block with one argument. So I would prefer not to introduce such kind of subtlety.
Because in general split should return two collections.