#FEATURE by exept
authorClaus Gittinger <cg@exept.de>
Mon, 09 Sep 2019 18:06:34 +0200
changeset 24773 b004df08089a
parent 24772 bcb134483fd9
child 24774 7c7a48047b0b
#FEATURE by exept class: SequenceableCollection added: #inGroupsOf:detect:thenDo:ifNone:
SequenceableCollection.st
--- a/SequenceableCollection.st	Mon Sep 09 16:15:21 2019 +0200
+++ b/SequenceableCollection.st	Mon Sep 09 18:06:34 2019 +0200
@@ -1,5 +1,3 @@
-"{ Encoding: utf8 }"
-
 "
  COPYRIGHT (c) 1989 by Claus Gittinger
 	      All Rights Reserved
@@ -5384,6 +5382,68 @@
     "Modified: / 27-10-2006 / 10:07:02 / cg"
 !
 
+inGroupsOf:n detect:anNArgBlock thenDo:anotherNArgBlock ifNone:exceptionValue
+    "evaluate the argument, anNArgBlock for every group of n elements in the collection,
+     until the block returns true. Then deliver the to anotherNArgBlock and return
+     that block's result. If none matches, return the valeu from exceptionValue.
+     An error will be reported, if the number of elements in the receiver
+     is not a multiple of n.
+     This is similar to slicesOf:detect:, but here, an N-arg block is expected."
+
+    |stop argVector|
+
+    stop := self size.
+
+    "/ the reason for inlining the cases for 2/3 args is to avoid the temporary object creation, and to    
+    "/ allow for the compiler (jitter) to generate better code for the block-call
+    n == 2 ifTrue:[
+        1 to:stop by:2 do:[:index |
+            |a1 a2|
+
+            a1 := self at:index.
+            a2 := self at:index+1.
+            (anNArgBlock value:a1 value:a2) ifTrue:[
+                ^ anotherNArgBlock value:a1 value:a2
+            ].
+        ].
+        ^ exceptionValue value.
+    ].
+    n == 3 ifTrue:[
+        1 to:stop by:3 do:[:index |
+            |a1 a2 a3|
+
+            a1 := self at:index.
+            a2 := self at:index+1.
+            a3 := self at:index+2.
+            (anNArgBlock value:a1 value:a2 value:a3) ifTrue:[
+                ^ anotherNArgBlock value:a1 value:a2 value:a3
+            ].
+        ].
+        ^ exceptionValue value.
+    ].
+
+    argVector := Array new:n.
+    1 to:stop by:n do:[:index |
+        argVector replaceFrom:1 to:n with:self startingAt:index.
+        (anNArgBlock valueWithArguments:argVector) ifTrue:[
+            ^ anotherNArgBlock valueWithArguments:argVector
+        ].
+    ].
+    ^ exceptionValue value.
+
+    "
+     #(1 one 2 two 3 three 4 four 5 five 6 six)
+         inGroupsOf:2 detect:[:num :sym | num > 3]
+         thenDo:[:num :sym | sym] ifNone:'ouch'   
+
+     #(1 one 2 two 3 three 4 four 5 five 6 six)
+         inGroupsOf:2 detect:[:num :sym | num > 99]
+         thenDo:[:num :sym | sym] ifNone:'ouch'      
+    "
+
+    "Modified: / 27-10-2006 / 10:07:02 / cg"
+!
+
 inGroupsOf:n do:anNArgBlock
     "evaluate the argument, anNArgBlock for every group of n elements in the collection.
      The block is called with n arguments for group of n consecutive elements in the receiver.