B4J Question [solved] How to make Map use efficient

Harris

Expert
Licensed User
Longtime User
As Erel suggested in his ETP lessons, one should not use GetKeyAt and GetValueAt in the fashion I have.

How to make this usage more efficient in my situation?

B4X:
Sub InitZones
 
Public currzone() As String   ' in class_globals....

' create a map on startup - once (InitZones) to be used throughout the session (24 hours).
' 
    Dim ls, i, j As Int
    Dim cnt As Long
    
    MastZonesMap.Initialize
    
    'tZM (zname As String, zpk As String, zspeed As String, ztype As String, zs1 As String, zs2 As String, zs3 As String, zs4 As String, zs5 As String, zcomment As String)
    
    PrevZone = 0
    inviol = False
    outviol = False
    zoneshowdevice = False
    zoneldflag = False
    ZoneName = "???"
    MaxRoadSpd = 46
    MaxRoadSpdgrc = 0
    trktype = 0
    inspdzone = False
    ViolMap.Initialize
    
    Dim lst1,lst2 As List
    lst1.Initialize
    lst2.Initialize
    
        
Try
    
    Dim c As Cursor
    c = DefCM.SQL1.ExecQuery("Select * FROM zonemast WHERE active = 1 order by mastpk desc")
    Dim setmax As Boolean = False
        Try

' create array of string (the map Values) and add to list
' create list of keys for the map...


            For i = 0 To c.RowCount - 1

                c.Position = i

                Dim tZMx() As String = Array As String( c.GetString("name"), c.GetString("mastpk"), c.GetString("speed"), c.GetString("stype"), c.GetString("s1"), c.GetString("s2") ,c.GetString("s3"), c.GetString("s4"), c.GetString("s5"), c.GetString("comment"))
                lst1.Add(c.GetString("mastpk"))
                lst2.Add(tZMx)
                
            Next
        Catch
            Log(" adding struc failed: "&LastException.Message)
    
        End Try
 
' make the master map of zones to evaluate once per second ( 30 zones (keys) )


        MastZonesMap = AddToMap(lst1,lst2,MastZonesMap)
 
        c.Close



' get all lat/lon points for each zone and add them to a pntMap 

        pntMap.Initialize

        For i = 0 To MastZonesMap.Size - 1
                
            c = DefCM.SQL1.ExecQuery("Select * from zonedet where mastpk = " & MastZonesMap.GetKeyAt(i))
            Dim points As Map
            points.Initialize
            Dim l1, l2 As Map
            l1.Initialize
            l2.Initialize
             'Log("added Mast Detail: "& zonemast.Get(i))

            For j = 0 To c.RowCount - 1   
                c.Position = j
                l1.Put(j, c.GetDouble("lat"))
                l2.Put(j, c.GetDouble("lon"))
            Next
    
            points.Put("lat", l1)
            points.Put("lon", l2)
            pntMap.Put(MastZonesMap.GetKeyAt(i) , points)
            c.Close
        Next
 
    zoneinit = True
Catch
 
   Log("zonemast table not created: "&LastException.Message)

End Try
 
End Sub




Sub AddToMap(KeyList As List, ValueList As List, ExistingMap As Map) As Map

' put keys and values into master map of zones...

    Private mapResult As Map : mapResult.Initialize
    
    If ExistingMap.IsInitialized Then
        mapResult = ExistingMap
    End If
  
    For i = 0 To KeyList.Size - 1
        mapResult.Put(KeyList.Get(i), ValueList.Get(i))
    Next
  
    Return mapResult
End Sub





Sub UpdateCurrZone
    
'  this runs each second.
' currzone = MastZonesMap.GetValueAt( i ) is suggested to be NOT the right way
' Erel suggests For Each...  
' How would YOU code this to make it clean and fast?

    
        For i = 0 To MastZonesMap.Size -1
            currzone = MastZonesMap.GetValueAt( i )
            pntLatList.Initialize
            pntLonList.Initialize
            Dim mp As Map
            mp.Initialize
            mp = pntMap.GetValueAt(i)
                
            Dim xl, yl As Map
            xl.Initialize
            yl.Initialize
            xl = mp.Get("lat")
            yl = mp.Get("lon")
    
            For j = 0 To xl.Size - 1   
                pntLatList.Add(xl.GetValueAt(j))
                pntLonList.Add(yl.GetValueAt(j))
            Next

' check where we are at in the world...  In a defined Zone ?
' pass current GPS lat/lon and check against zone polygon...

            WasInZone = CheckPointInPolygone(pntLatList.Size, pntLatList, pntLonList, GPSServMod.gLoc.fLongitude, GPSServMod.gLoc.fLatitude, currzone(z_pk), currzone(z_name)  )
            
            If WasInZone Then
' if in any zone - break from the loop since further processing is redundant...
               Exit
            End If
            
        Next

' do other stuff - like record if vehicle speed > than "x" for the current zone...

End Sub

Thanks
 

Erel

B4X founder
Staff member
Licensed User
Longtime User
You are asking about this loop, right?

B4X:
  For i = 0 To MastZonesMap.Size - 1
               
            c = DefCM.SQL1.ExecQuery("Select * from zonedet where mastpk = " & MastZonesMap.GetKeyAt(i))
            Dim points As Map
            points.Initialize
            Dim l1, l2 As Map
            l1.Initialize
            l2.Initialize
             'Log("added Mast Detail: "& zonemast.Get(i))

            For j = 0 To c.RowCount - 1  
                c.Position = j
                l1.Put(j, c.GetDouble("lat"))
                l2.Put(j, c.GetDouble("lon"))
            Next
   
            points.Put("lat", l1)
            points.Put("lon", l2)
            pntMap.Put(MastZonesMap.GetKeyAt(i) , points)
            c.Close
        Next
Assuming that the key and values are strings:
B4X:
For Each key As String In MastZonesMap.Keys
 Dim Value As String = MastZonesMap.Get(key) 'you are not using it here
 
c = DefCM.SQL1.ExecQuery2("Select * from zonedet where mastpk = ?", Array(key)) 'always better to use parameterized queries.
            Dim points As Map
            points.Initialize
            Dim l1, l2 As Map
            l1.Initialize
            l2.Initialize
             'Log("added Mast Detail: "& zonemast.Get(i))

            For j = 0 To c.RowCount - 1  
                c.Position = j
                l1.Put(j, c.GetDouble("lat"))
                l2.Put(j, c.GetDouble("lon"))
            Next
  
            points.Put("lat", l1)
            points.Put("lon", l2)
            pntMap.Put(key , points)
            c.Close
Next
 
Upvote 0

Harris

Expert
Licensed User
Longtime User
That was the initialize section - run only once...

It is more about this section here....
This executes every second, so - currzone = MastZonesMap.GetValueAt( i ) may be slow and dangerous?


B4X:
Sub UpdateCurrZone
    
'  this runs each second.
' currzone = MastZonesMap.GetValueAt( i ) is suggested to be NOT the right way
' Erel suggests For Each... 
' How would YOU code this to make it clean and fast?

    
        For i = 0 To MastZonesMap.Size -1
            currzone = MastZonesMap.GetValueAt( i )
 
Upvote 0

Harris

Expert
Licensed User
Longtime User
Functions with removed GetKeyAt and GetValueAt
Thanks


B4X:
Sub UpdateCurrZone
    
        'For i = 0 To MastZonesMap.Size -1
        For Each key As String In MastZonesMap.Keys
            Dim Value As Object = MastZonesMap.Get(key)             
            currzone = Value                                            'MastZonesMap.GetValueAt(  i )
            
            pntLatList.Initialize
            pntLonList.Initialize
            Dim mp As Map
            mp.Initialize
            
            Dim V As Object = pntMap.Get( key )            
            mp = V 'pntMap.GetValueAt(i)
            
            beepcnt  = currzone(z_speed)
                
            Dim xl, yl As Map
            xl.Initialize
            yl.Initialize
            xl = mp.Get("lat")
            yl = mp.Get("lon")
    
            For j = 0 To xl.Size - 1   
                pntLatList.Add( xl.Get(j) )     '  GetValueAt(j) )
                pntLonList.Add( yl.Get(j) )    '  GetValueAt(j) )
            Next


            WasInZone = CheckPointInPolygone(pntLatList.Size, pntLatList, pntLonList, GPSServMod.gLoc.fLongitude, GPSServMod.gLoc.fLatitude, currzone(z_pk), currzone(z_name)  )
            
            If WasInZone Then
               Exit
            End If
            
        Next
End Sub
 
Upvote 0
Top