B4J Question I wonder about maps: Use objects as key and Using smartstring as key

knutf

Active Member
Licensed User
Longtime User
Hello

My first wonder:
B4X language guid states about map collections that "The key should be a string or a number". Why is that true? I've been using objects as key a lot and for me it seems to work without problems!

My other wonder:
I have a problem where I want to use 2 numbers as a key in a map. I came up with a solution where I use smartstrings to create the key. Look at the code and log output below to see what I mean.

What do you think about doing it that way? Does my code provide effective lookups in the map collection?

B4J Non-UI application:
Sub Process_Globals
    Type keyStruct (firstKey As Int, secondKey As Long)
End Sub

Sub AppStart (Args() As String)
    Dim key1 As keyStruct = CreatekeyStruct(1,50)
    Dim key2 As keyStruct = CreatekeyStruct(1,51)
    Dim key3 As keyStruct = CreatekeyStruct(2,50)
    Dim otherKey3 As keyStruct = CreatekeyStruct(2,50)
    
    Dim MapWithSmartstringKeys As Map = CreateMap( _
            $"${key1}"$:"value 1", _
            $"${key2}"$:"value 2", _
            $"${key3}"$:"value 3")

    Dim MapWithRegularUseOfKeys As Map = CreateMap( _
            key1:"value 1", _
            key2:"value 2", _
            key3:"value 3")


    Log("-- MapWithSmartstringKeys --")
    Log(MapWithSmartstringKeys.Getdefault($"${key1}"$,"key1 didn't look up av value"))
    Log(MapWithSmartstringKeys.Getdefault($"${CreatekeyStruct(1,51)}"$,"CreatekeyStruct(1,51) didn't look up av value"))
    Log(MapWithSmartstringKeys.Getdefault($"${otherKey3}"$,"otherKey3 didn't look up av value"))
    Log(" ")
    Log("-- MapWithRegularUseOfKeys --")
    Log(MapWithRegularUseOfKeys.Getdefault(key1,"key1 didn't look up av value"))
    Log(MapWithRegularUseOfKeys.Getdefault(CreatekeyStruct(1,51),"CreatekeyStruct(1,51) didn't look up av value"))
    Log(MapWithRegularUseOfKeys.Getdefault(otherKey3,"otherKey3 didn't look up av value"))   
End Sub


Public Sub CreatekeyStruct (firstKey As Int, secondKey As Long) As keyStruct
    Dim t1 As keyStruct
    t1.Initialize
    t1.firstKey = firstKey
    t1.secondKey = secondKey
    Return t1
End Sub

Log output:
-- MapWithSmartstringKeys --
value 1
value 2
value 3
 
-- MapWithRegularUseOfKeys --
value 1
CreatekeyStruct(1,51) didn't look up av value
otherKey3 didn't look up av value
 

Attachments

  • MapTestNonUI.zip
    1 KB · Views: 75

William Lancee

Well-Known Member
Licensed User
Longtime User
You have quite a bit of stuff going on here.
1. putting the keys in a smart string is the same as casting them as a string
B4X:
    Dim key1 As keyStruct = CreatekeyStruct(1,50)
    Log($"${key1}"$)
    '[IsInitialized=true, firstKey=1, secondKey=50]

2. The string of otherkey3 is the same as the string of key3, so that is what you're going to get the value of
3. The keys as objects work as expected (at least by me)
a. key1 gives value 1
b. the CreatekeyStruct(1,51) is a different object from key2
c. MapWithRegularUseOfKeys does not have a otherkey3 entry
 
Last edited:
Upvote 0

William Lancee

Well-Known Member
Licensed User
Longtime User
If you want to retrieve the value from key combination, then combine the keys in some way
Using a custom Type as string works, but seems like overkill.

B4X:
        'for example:
        Dim ki As Int = 10000 * firstkey + secondkey 
        'or:
        Dim ks As String = firstKey & TAB & secondKey
 
Upvote 0

knutf

Active Member
Licensed User
Longtime User
If you want to retrieve the value from key combination, then combine the keys in some way
Using a custom Type as string works, but seems like overkill.

B4X:
        'for example:
        Dim ki As Int = 10000 * firstkey + secondkey
        'or:
        Dim ks As String = firstKey & TAB & secondKey
Yes, that's what I want: Get the value from the key combination. Doing so by putting the structure in a smartstring is a way to combine the values into a string, with little code.

What I'm wondering is if the rest of you think this is an effective way to do it. The string will be relatively long. Does that make the time consumption of the lookup in the map bigger?

Another way to produce the same key is:
B4X:
MapWithSmartstringKeys.Get(key1.as(String)) 'ignore

I think it looks better, but the produced key is the same: [IsInitialized=true, firstKey=1, secondKey=50]
 
Upvote 0

knutf

Active Member
Licensed User
Longtime User
Another way to make the code short is to create a custom sub that convert the struct to a string:

B4X:
Public Sub keyAsString(key As keyStruct) As String
    Return key.firstKey & TAB & key.secondKey
End Sub

And use it like this:
B4X:
    Log(MapWithCustomStringKeys.Get(keyAsString(key1)))
    Log(MapWithCustomStringKeys.Get(keyAsString(CreatekeyStruct(1,51))))
 
Upvote 0

Erel

B4X founder
Staff member
Licensed User
Longtime User
1. Smart strings is a compiler feature. The generated string is a regular string.

2. You can use objects as keys. With a few exceptions such as Lists, the keys will only match when you use the exact same object.

B4X:
Sub AppStart (Args() As String)
    Dim n1() As Int = Array As Int(1, 2)
    Dim n2() As Int = Array As Int(1, 2)
    Dim m As Map = CreateMap(n1: "a", n2: "b")
    Log(m.Size) '2

    Dim l1 As List = Array As Int(1, 2)
    Dim l2 As List = Array As Int(1, 2)
    Dim m As Map = CreateMap(l1: "a", l2: "b")
    Log(m.Size) '1
End Sub
 
Upvote 0
Top