Forum Discussion

joetesta's avatar
joetesta
Roku Guru
9 years ago

Convert String -> roString ?

Background:  I have an Associative Array and one of the fields is a String.  After retrieving that string, want to check if it's already in an existing array (roArray) and using Komag's "in array" example from here [/url:2dxfavf6]  Issue is that the types don't match since the "for each" gives us roString's whereas the value I'm comparing is a String.

Is there an easy way to turn the String into an roString, or if I should just remove the 'type' check and only compare the values?

tyvmia,
Joe

10 Replies

  • "joetesta" wrote:
    Is there an easy way to turn the String into an roString...?



    Box("String value")
  • If you know the list will contain only string-ish things, just forgo the "type()" check. String comparison knows how to sort things out between the different varieties of strings. 

    The reason Komag is checking type() is - i presume - in his case there might be different objects in the list, say numbers - and B/S bombs (takes exception) when trying to compare different types instead of returning False. 

    See also at the end of that thread, my suggestion to use roAA for such checks if the set is big.
  • Yes, EnTerr is right, I only checked the Type to avoid a crash if you have a mixed array containing integers, booleans, strings, arrays, etc. But it was a quick and sloppy example which only works most of the time (because most of the time your strings will all be "String" or all be "roString". But of course, as you've discovered, sometimes you have a mix of those too.

    You could check both things to be EITHER "String" or "roString" and only then check them against each other. Or as Enterr suggests, if you know they will all be string things anyway, just check whether they're equal without checking for Type.
  • Thank you for the replies!
    Unfortunately belltown's solution doesn't work
    "belltown" wrote:

    Box("String value")



       Id = myAssocArray.Id
       Id = Id.ToStr()
       ? "Got the Id: "; Id; " - Id type is "; type(Id)
       Id = box(Id)
       ? "Now Id type is "; type(Id)

    output:
    Got the Id: 82547 - Id type is String
    Now Id type is String

    I will try one of the other solutions; 
     if (type(i) = type(value) OR ((type(i) = "String" OR type(i) = "roString") AND (type(value) = "String" OR type(value) = "roString"))) 
    AND i = value then return TRUE

    Or probably just ignoring type is safe enough for this situation.
    Thanks again!
    Joe
  • joetesta - good grief, you are trying too hard!
    You shouldn't worry about differences between the string types in B/S - there are if i remember about 6 hidden types of strings. If you really, really want to check for string, do this
    if getInterface(x, "ifString") <> invalid then ...
    and it will cover all cases, see viewtopic.php?f=34&t=67449 for discussion.

    But what are you even trying to accomplish? If you can state your problem more generally, we can probably suggest a better/faster solution with roAAs
  • "joetesta" wrote:

    Unfortunately belltown's solution doesn't work
    "belltown" wrote:

    Box("String value")



       Id = myAssocArray.Id
       Id = Id.ToStr()
       ? "Got the Id: "; Id; " - Id type is "; type(Id)
       Id = box(Id)
       ? "Now Id type is "; type(Id)

    output:
     Got the Id: 82547 - Id type is String
     Now Id type is String

    That's not strictly true. Your Id variable really is an roString, and box(Id) really did ensure that it was an roString and not a String. The problem is that the BrightScript Type() function by default returns a BrightScript 2.1-compatible type value, which for some strings will return "String" when the type really is "roString". To guarantee that the correct BrightScript 3 string type is returned, you need to add the "3" parameter:

    myAssocArray = {Id: 42}

    BrightScript Debugger> Id = myAssocArray.Id

    BrightScript Debugger> Id = Id.ToStr()

    BrightScript Debugger> ? "Got the Id: "; Id; " - Id type is "; type(Id)
    Got the Id: 42 - Id type is String

    BrightScript Debugger> Id = box(Id)

    BrightScript Debugger> var
    global           rotINTERFACE:ifGlobal
    m                roAssociativeArray refcnt=2 count:0
    id               roString (2.1 was String) refcnt=1 val:"42"
    myassocarray     roAssociativeArray refcnt=1 count:1

    BrightScript Debugger> ? "Now Id type is "; type(Id)
    Now Id type is String

    BrightScript Debugger> ? "The Id type really is "; type(Id, 3)
    The Id type really is roString

    Or check that Type(Id) is a "String" or "roString" -- or do whar EnTerr said above and use GetInterface().
  • "EnTerr" wrote:

    But what are you even trying to accomplish? If you can state your problem more generally, we can probably suggest a better/faster solution with roAAs


    Trying to see if an integer is already in the array of strings so it doesn't get added twice. With the original code, it would be added since the types didn't match.
    This code works with what i have now. Either element can be either String or roString and it will find the match.
    But glad to learn more, thanks!!
  • "belltown" wrote:
    To guarantee that the correct BrightScript 3 string type is returned, you need to add the "3" parameter:

    Good to know - tested and this method works!

    "belltown" wrote:
    Or check that Type(Id) is a "String" or "roString"

    Yep that's what I did with my long "if" line, but EnTerr didn't like it - hey, it works! 🙂
    Thanks for all your help!
    Joe
  • "joetesta" wrote:
    "belltown" wrote:
    Or check that Type(Id) is a "String" or "roString"

    Yep that's what I did with my long "if" line, but EnTerr didn't like it - hey, it works! 🙂

    EnTerr does not like doing "busy-work".
    You will stop liking it too, if and when your list grows past 1000 elements - because you keep walking over and checking most of them, most of the time.
    Instead you should be checking against roAssociativeArray - that costs you O(1) vs O(n). 

    Whoosh? 🙂 Let me demonstrate:
    BrightScript Debugger> arr = []: hash = {}: for i=1 to 1000: s = str(i): arr.push(s): hash[s] = i-1: next

    BrightScript Debugger> find1 = function(arr, el): i=0: while i < arr.count() and arr[i] <> el: i+=1: end while: return i: end function
    BrightScript Debugger> ? find1(arr, " 7"), find1(arr, "7")
    6               1000

    BrightScript Debugger> find2 = function(hash, el): return hash[el]: end function
    BrightScript Debugger> ? find2(hash, " 7"), find2(hash, "7")
    6              invalid
    So far, so good?
    BrightScript Debugger> ti = createObject("roTimeSpan")
    BrightScript Debugger> ti.mark(): for j=1 to 1000: find1(arr, str(i)): next: ? ti.totalMilliSeconds()
    5246

    BrightScript Debugger> ti.mark(): for j=1 to 1000: find2(hash, str(i)): next: ? ti.totalMilliSeconds()
    45
     We just demonstrated rummaging in linear fashion being 100x slower.
  • "EnTerr" wrote:
     We just demonstrated rummaging in linear fashion being 100x slower.


    OK that's great, the reason I have an array and not an Associative array is that I'm using the 'split' function on a string that's comma separated values stored in roRegistry.

    Is there a convenient way to store an AA in registry?  Update: It appears there is, FormatJson

    thanks EnTerr

    in this particular case, this array will never have more than 10 elements;
    if meHeartyarray.Count() > 9
       ' already have 10 saved in meHeartyarray, drop the oldest'
        meHeartyarray.shift()
     end if