class: SequenceableCollection
authorClaus Gittinger <cg@exept.de>
Mon, 21 Jan 2013 14:44:42 +0100
changeset 14674 672133ad1b1b
parent 14673 d3c91be01e96
child 14675 26182ff5b045
class: SequenceableCollection added: #joinWith: methods comment/format in:5 methods
SequenceableCollection.st
--- a/SequenceableCollection.st	Sat Jan 19 16:50:27 2013 +0100
+++ b/SequenceableCollection.st	Mon Jan 21 14:44:42 2013 +0100
@@ -606,6 +606,21 @@
     ^ self copyFrom:2
 !
 
+joinWith:separatingElement
+    "return a collection generated by concatenating my elements
+     and embedding separatingElement in between.
+     Similar to asStringWith:, but not specifically targeted towards collections of strings."
+
+    ^ self
+        joinWithAll:(Array with:separatingElement)
+        from:1 to:(self size) as:nil
+
+    "
+     #('hello' 'world' 'foo' 'bar' 'baz') joinWith:$;   
+     #('hello' 'world' 'foo' 'bar' 'baz') joinWith:$|
+    "
+!
+
 shuffled
     "return a randomly shuffled copy of the receiver"
 
@@ -668,7 +683,6 @@
     ^ self replaceFrom:start to:stop with:anArray startingAt:repStart
 ! !
 
-
 !SequenceableCollection methodsFor:'accessing'!
 
 after:anObject
@@ -2390,7 +2404,8 @@
 asStringWith:sepChar
     "return a string generated by concatenating my elements
      (which must be strings or nil) and embedding sepChar characters in between.
-     Nil entries and empty strings are counted as empty lines."
+     Nil entries and empty strings are counted as empty lines.
+     Similar to joinWith:, but specifically targeted towards collections of strings."
 
     ^ self
         from:1 to:(self size)
@@ -2410,13 +2425,14 @@
 asStringWith:sepCharacter from:firstLine to:lastLine
     "return part of myself as a string with embedded sepCharacters.
      My elements must be strings or nil; nil entries and empty strings are
-     taken as empty lines."
+     taken as empty lines.
+     Similar to joinWith:, but specifically targeted towards collections of strings."
 
     ^ self
-	from:firstLine to:lastLine
-	asStringWith:sepCharacter
-	compressTabs:false
-	final:nil
+        from:firstLine to:lastLine
+        asStringWith:sepCharacter
+        compressTabs:false
+        final:nil
     "
      creating entries for searchpath:
 
@@ -2434,14 +2450,15 @@
      taken as empty lines.
      If the argument compressTabs is true, leading spaces are converted
      to tab-characters (8col tabs). The last line is followed by a final
-     character (if non-nil)."
+     character (if non-nil).
+     Similar to joinWith:, but specifically targeted towards collections of strings."
 
     ^ self
-	from:firstLine to:lastLine
-	asStringWith:sepCharacter
-	compressTabs:compressTabs
-	final:endCharacter
-	withEmphasis:true
+        from:firstLine to:lastLine
+        asStringWith:sepCharacter
+        compressTabs:compressTabs
+        final:endCharacter
+        withEmphasis:true
 
     "Modified: / 17.6.1998 / 12:31:19 / cg"
 !
@@ -2459,14 +2476,15 @@
      any emphasis. If false, a plain string is returned.
      This method is tuned for big collections, in not creating many
      intermediate strings (has linear runtime). For very small collections
-     and small strings, it may be faster to use the comma , operation."
+     and small strings, it may be faster to use the comma , operation.
+     Similar to joinWith:, but specifically targeted towards collections of strings."
 
     ^ self
-	from:firstLine to:lastLine
-	asStringWith:sepCharacter
-	compressTabs:compressTabs
-	final:endCharacter
-	withEmphasis:withEmphasis
+        from:firstLine to:lastLine
+        asStringWith:sepCharacter
+        compressTabs:compressTabs
+        final:endCharacter
+        withEmphasis:withEmphasis
 !
 
 asStringWithCRs
@@ -2531,11 +2549,11 @@
      to tab-characters (8col tabs). WithCR controls whether the last line
      should be followed by a cr or not."
 
-    ^ self asStringWith:(Character cr)
-		   from:firstLine
-		     to:lastLine
-	   compressTabs:compressTabs
-		  final:(withCR ifTrue:[Character cr] ifFalse:[nil])
+    ^ self 
+        asStringWith:(Character cr)
+        from:firstLine to:lastLine
+        compressTabs:compressTabs
+        final:(withCR ifTrue:[Character cr] ifFalse:[nil])
 !
 
 decodeAsLiteralArray
@@ -2892,6 +2910,87 @@
     "Modified: / 17.6.1998 / 12:31:59 / cg"
 !
 
+joinWithAll:separatingCollection
+    "return a collection generated by concatenating my elements
+     and slicing separatingCollection in between.
+     Similar to asStringWith:, but not specifically targeted towards collections of strings."
+
+    ^ self
+        joinWithAll:separatingCollection
+        from:1 to:(self size) as:nil
+
+    "
+     #('hello' 'world' 'foo' 'bar' 'baz') joinWithAll:' ; '   
+     #('hello' 'world' 'foo' 'bar' 'baz') joinWithAll:' | '
+    "
+!
+
+joinWithAll:separatingCollection from:startIndex to:endIndex as:speciesOrNil 
+    "extract parts of myself as a new collection with optional embedded separator.
+     Separator may be nil, or a collection of elements to be sliced in between.
+     SpeciesOrNil specifies the species of the resultig object, allowing for Arrays to be converted
+     as OrderedCollection or vice versa on the fly. If nil is passed in, the species of the first non-nil
+     element is used.
+     This counts the overall size first, then allocates the new collecton once and replaces elements
+     via bulk copies. For very small collections, it may be faster to use the comma , operation.
+     Similar to asStringWith:, but not specifically targeted towards string handling."
+
+    |totalLength "{ Class:SmallInteger }"
+     pos         "{ Class:SmallInteger }"
+     sepCnt      "{ Class:SmallInteger }"
+     subColl newColl 
+     species|
+
+    startIndex = endIndex ifTrue:[ ^ self at:startIndex ].
+
+    species := speciesOrNil.
+
+    "
+     first accumulate the size of the result, 
+     to avoid countless reallocations.
+    "
+    totalLength := 0.
+    sepCnt := separatingCollection size.
+
+    startIndex to:endIndex do:[:index |
+        subColl := self at:index.
+        totalLength := totalLength + subColl size.
+        species isNil ifTrue:[
+            subColl notNil ifTrue:[
+                species := subColl species
+            ]
+        ]
+    ].
+    totalLength := totalLength + ((endIndex - startIndex) * sepCnt).
+    newColl := species withSize:totalLength.
+
+    pos := 1.
+    startIndex to:endIndex do:[:index |
+        subColl := self at:index.
+        subColl size ~~ 0 ifTrue:[
+            newColl replaceFrom:pos with:subColl startingAt:1.
+            pos := pos + subColl size.
+        ].
+        ((sepCnt ~~ 0) and:[index ~~ endIndex]) ifTrue:[
+            newColl replaceFrom:pos to:(pos+sepCnt-1) with:separatingCollection startingAt:1.
+            pos := pos + sepCnt.
+        ].
+    ].
+
+    ^ newColl
+
+    "
+     #( 'aa' 'bb' '' 'cc' ) joinWith:'|' from:1 to:4 as:String  
+     #( 'aa' 'bb' '' 'cc' ) joinWith:nil from:1 to:4 as:String  
+     #( 'aa' 'bb' '' 'cc' ) joinWith:'|' from:1 to:4 as:Array   
+     #( (1 2 3) (4 5 6) (7 6 8) ) joinWith:#(nil) from:1 to:3 as:OrderedCollection  
+     #( (1 2 3) (4 5 6) (7 6 8) ) joinWith:nil from:1 to:3 as:nil                
+    "
+
+    "Created: / 17.6.1998 / 12:30:32 / cg"
+    "Modified: / 17.6.1998 / 12:31:59 / cg"
+!
+
 subCollections:aBlock 
     "Answser an ordered collection of ordered collections
      where each subcollection is delimited by an element of the receiver
@@ -8733,11 +8832,11 @@
 !SequenceableCollection class methodsFor:'documentation'!
 
 version
-    ^ '$Header: /cvs/stx/stx/libbasic/SequenceableCollection.st,v 1.328 2013-01-01 11:30:33 cg Exp $'
+    ^ '$Header: /cvs/stx/stx/libbasic/SequenceableCollection.st,v 1.329 2013-01-21 13:44:42 cg Exp $'
 !
 
 version_CVS
-    ^ '$Header: /cvs/stx/stx/libbasic/SequenceableCollection.st,v 1.328 2013-01-01 11:30:33 cg Exp $'
+    ^ '$Header: /cvs/stx/stx/libbasic/SequenceableCollection.st,v 1.329 2013-01-21 13:44:42 cg Exp $'
 ! !