Roku Developer Program

Developers and content creators—a complete solution for growing an audience directly.
cancel
Showing results for 
Search instead for 
Did you mean: 
EnTerr
Level 8

"Join()" counterpart to roString.Split()? [done!]

I found myself wishing today there was the opposite function to ifString.Split() - i.e. if Split() "explodes" string to pieces, there be a function that "implodes" pieces to a string.

A good illustration of the need is this thread viewtopic.php?f=34&t=96379 - say i am writing a url-encode function - can the new string be constructed by appending character after character - sure, but that's a lot of churn. Instead if i can blow the string into array of 1-char strings, replace some of them and join them into one, that would be fancy.

So, a proposal - to define a function or method that can do that. Something with signature like:

  1. ifEnum.joinToStr(sep as String=""), e.g. .joinToStr()

  2. ifStringOps.join(list as ifEnum), e.g. )

  3. ifGlobal.strJoin(sep as String="", list as ifEnum), e.g. )
How would such a mythical creature work? Enumerate the collection, calling toStr() on each element and then join them with separator between (i threw ifEnum and toStr() in in attempt at generality).

Discussion: (3) probably not likely to happen for concerns of polluting the global namespace. (2) is the tack Python takes, it's pure in the sense keeps the method in the String namespace but in my experience confusing to beginners (as me at the time) whose intuition is the reverse method to be invoked on the array, i.e. (1).

Just an idea, it's a "nice to have" feature.
0 Kudos
8 Replies
EnTerr
Level 8

Re: "Join()" counterpart to roString.Split() ?

Good grief - i had forgotten indexing Roku strings is O(len) and not O(1):
BrightScript Debugger> s = string(30000, "s"): tm = createObject("roTimeSpan")
BrightScript Debugger> tm.mark(): for each ch in s.split(""): next: ? tm.totalMilliSeconds()
97

BrightScript Debugger> tm.mark(): for i=1 to len(s): ch = mid(s,i,1): next: ? tm.totalMilliSeconds()
2614

26x slower? That's +1 argument for using the explode/implode approach!
0 Kudos
Komag
Level 9

Re: "Join()" counterpart to roString.Split() ?

I apologize for being ignorant, but could FormatJson() help in any way?
0 Kudos
EnTerr
Level 8

Re: "Join()" counterpart to roString.Split() ?

"Komag" wrote:
I apologize for being ignorant, but could FormatJson() help in any way?

How so? Let me draft some sample code - say rot47 "cipher" - can you make it work with formatJSON() :
function rot47(s):
 a = s.split("")
 for i = 0 to a.count()-1:
   j = asc(a[i]): if j > 32 and j < 127 then a[i] = chr(33 + ((j + 14) mod 94))
 next
 return "".join(a) 'make-believe method'
end function
0 Kudos
Highlighted
belltown
Level 7

Re: "Join()" counterpart to roString.Split() ?

Strings are slow, byte arrays are faster.

Sub Main ()
   s = string(30000, "s"): tm = createObject("roTimeSpan")
   tm.mark(): ss = s.split(""): ? tm.totalMilliSeconds()
   tm.mark(): join1 = joinSlow (ss) : ? tm.totalMilliSeconds()
   tm.mark(): join2 = joinFast (ss) : ? tm.totalMilliSeconds()
End Sub

Function joinSlow (strArray As Object, sep = "" As String) As String
   joined = ""
   strArrayLen = strArray.Count ()
   If strArrayLen > 0
       joined = strArray [0]
   End If
   For i = 1 To strArrayLen - 1
       joined = joined + sep + strArray [i]
   End For
   Return joined
End Function

Function joinFast (strArray As Object, sep = "" As String) As String
   joined  = CreateObject ("roByteArray")
   sbytes  = CreateObject ("roByteArray")
   sepba   = CreateObject ("roByteArray")
   sepba.FromAsciiString (sep)
   strArrayLen = strArray.Count ()
   If strArrayLen > 0
       joined.FromAsciiString (strArray [0])
   End If
   For i = 1 To strArrayLen - 1
       sbytes.FromAsciiString (strArray [i])
       joined.Append (sepba)
       joined.Append (sbytes)
   End For
   Return joined.ToAsciiString ()
End Function



------ Running dev 'Junk' main ------
457
6958
462
https://github.com/belltown/
0 Kudos
EnTerr
Level 8

Re: "Join()" counterpart to roString.Split() ?

"belltown" wrote:
Strings are slow, byte arrays are faster.

Sheesh... you Sir just brought a roByteArray into a String fight!  Smiley Happy
Even with byte arrays though, join is ~3x slower than it would be native.

On a side note, i can 2x speed up your joinSlow() as:
function joinStrArr(strArray as object, sep = "" as string) as string
   joined = ""
   for each s in strArray:
       joined += sep + s
   next
   return joined.mid(len(sep))
end function

PS. bugfix, "return joined" -> "return joined.mid(len(sep))"
0 Kudos
belltown
Level 7

Re: "Join()" counterpart to roString.Split() ?

"EnTerr" wrote:
On a side note, i can 2x speed up your joinSlow() as:
function joinStrArr(strArray as object, sep = "" as string) as string
   joined = ""
   for each s in strArray:
       joined += sep + s
   next
   return joined
end function



But then you'd end up with a spurious separator at the start of the joined string.

Both my functions could be further optimized though, e.g. handling the special case separately where the separator is the empty string.
https://github.com/belltown/
0 Kudos
EnTerr
Level 8

Re: "Join()" counterpart to roString.Split() ?

"belltown" wrote:
But then you'd end up with a spurious separator at the start of the joined string.
Oops. Trivial bug, fixed by "return joined.mid(len(sep))"

Both my functions could be further optimized though, e.g. handling the special case separately where the separator is the empty string.

... or in fancy future, array join function can be added to B/S. Thinking of it, I'd like to propose a generous criterion like
"If all four of Lua, Python, Ruby, Javascript have a certain utility function, so should BrightScript"
(of these, Lua is the most spartan - so if even Lua has it... wink-wink, nudge-nudge)
0 Kudos
EnTerr
Level 8

Re: "Join()" counterpart to roString.Split()? [done!]

i notice that roArray.Join(separtor) has appeared in 7.5, maybe as answer to this question. Funny that someone forgot to mention it in the Release Notes. Was it for fear to set precedent of listening to outside developers, i wonder?

Brightscript Debugger> ? "*" + ["bing", "bing", "bong"].join(" ") + "*"
*bing bing bong*

All hail the wizards of Roku, the great and powerful ! Smiley Wink
0 Kudos