B4J Code Snippet [BANano] Map Get / Put Recursively ... perhaps a B4X wish...

Ola

With the jsPDF library that i'm using, the data structures are deeply imbedded, for example.

B4X:
data.cell.styles.textColor = [0. 255. 50]

So I was thinking, what if one was able to recursively execute a map get/set using a path?

In normal circumstances to create a map object like this tree structure (image from console.log)

1624125719118.png


One has to write source code like this..

B4X:
Dim m As Map = CreateMap()
    Dim user As Map = CreateMap()
    Dim address As Map = CreateMap()
    address.Put("addressline1", "")
    address.Put("addressline2", "")
    address.Put("city", "")
    address.Put("province", "")
    address.Put("country", "")
    user.put("firstname", "")
    user.Put("lastname", "")
    user.Put("address", address)
    m.Put("user", user)

Comes in RecursivePut... (for BANano)

B4X:
Sub RecursivePut(data As Map, path As String, value As Object)
    Dim prevObj As BANanoObject = data
    Dim items As List = BANano.Split(".", path)
    Dim iTot As Int = items.Size
    Dim iCnt As Int
    '
    Dim strprev As String = ""
    Dim prtObj As BANanoObject
    Dim litem As String = items.Get(iTot - 1)
    '
    For iCnt = 1 To iTot - 1
        'get the previos path
        strprev = items.Get(iCnt - 1)
        'the parent object
        prtObj = prevObj.GetField(strprev)
        'this does not exist, create it
        If BANano.IsUndefined(prtObj) Then
            Dim no As Object
            prevObj.SetField(strprev, no)
            prevObj = prevObj.GetField(strprev)
        Else
            prevObj = prtObj
        End If
    Next
    prevObj.SetField(litem, value)
End Sub

So if we run this example, even, if the map is initialized empty

B4X:
Dim m as Map = CreateMap()
RecursivePut(m, "user.firstname", "Anele")
    RecursivePut(m, "user.lastname", "Mbanga")
    RecursivePut(m, "user.address.addressline1", "40.71")
    RecursivePut(m, "user.address.addressline2", "-73.98")
    RecursivePut(m, "user.address.city", "Moon Colony")
    RecursivePut(m, "user.address.province", "Close to Mars")
    RecursivePut(m, "user.address.country", "Outer Space")
    RecursivePut(m, "user.firstname", "Ozzie")
    RecursivePut(m, "user.loves", "B4X")

We get (image from console.log)

1624126307405.png



Imma try and get the Get working....

Enjoy!
 
Last edited:

alwaysbusy

Expert
Licensed User
Longtime User
A nice idea. Maybe this can give you some inspiration for the GET (e.g. to use wildcards and queries):


PS: BANanoShared.StrParse is just BANAno.Split but returns a List and not (), same thing anyway.
What error do you get if you use a list? Looks fine with this code:

B4X:
Dim splList As List = BANano.Split(".", "alain.is.here")
For i = 0 To splList.Size - 1
        Log(splList.Get(i))
Next

' result:
alain
is
here

Alwaysbusy
 

Mashiane

Expert
Licensed User
Longtime User
Let's Recursively get map items

B4X:
RecursiveGet(m, "user.loves")

Returns B4X

B4X:
RecursiveGet(m, "user.address.country")
Outer Space

B4X:
RecursiveGet(m, "user")

{
address: {addressline1: "40.71", addressline2: "-73.98", city: "Moon Colony", province: "Close to Mars", country: "Outer Space"}
firstname: "Ozzie",
lastname: "Mbanga",
loves: "B4X"}

B4X:
RecursiveGet(m, "user.address")

Here is the sub

B4X:
Sub RecursiveGet(data As Map, path As String) As Object
    Dim prevObj As BANanoObject = data
    Dim items As List = BANano.Split(".", path)
    Dim iTot As Int = items.Size
    Dim iCnt As Int
    '
    Dim strprev As String = ""
    Dim prtObj As BANanoObject
    Dim litem As String = items.Get(iTot - 1)
    '
    For iCnt = 1 To iTot - 1
        'get the previos path
        strprev = items.Get(iCnt - 1)
        'the parent object
        prtObj = prevObj.GetField(strprev)
        'this does not exist, return
        If BANano.IsUndefined(prtObj) Then
            Return Null
        Else
            prevObj = prtObj
        End If
    Next
    Dim res As Object = prevObj.GetField(litem)
    Return res
End Sub

Ta!
 
Last edited:
Top