B4J Question Compare Two Maps

cklester

Well-Known Member
Licensed User
I guess I can move this to the tutorials section, since this seems to work just fine:

B4X:
Sub BuffersEqual (b1() As Byte, b2() As Byte) As Boolean
    If b1.Length <> b2.Length Then Return False
    For i = 0 To b1.Length - 1
        If b1(i) <> b2(i) Then Return False
    Next
    Return True
End Sub

'name this whatever you want!
Public Sub MapsAreSame(aMap as Map, bMap as Map) As Boolean
    Dim ser As B4XSerializator
    Dim am() As Byte = ser.ConvertObjectToBytes(aMap)
    Dim bm() As Byte = ser.ConvertObjectToBytes(bMap)
    Return BuffersEqual(am,bm)
End Sub

Is this an acceptable way to do it?
 
Last edited:

udg

Expert
Licensed User
Longtime User
Row 25:
If Not(isSame(mp1.Get(Key),mp2.Get(Key))) Then
I was curious on what could happen if Key wasn't available in map2. We all know that mp2.Get will return a Null, but how will ConvertObjectToBytes react? An empty array?
A quick test showed that a Null gets converted to a 9-bytes array (120,-100,99,0,0,0,1,0,1), kind of a signature for Null.

So, a failure point (admittedly, an edge-case) could be when a Key present in mp1 and not in mp2 leads to a value of Null. Something like:
B4X:
Dim mp1 As Map
    Dim mp2 As Map
    mp1.Initialize
    mp2.Initialize
    mp1.Put("one",Null)
    mp2.Put("two", 2)
..
If Not(isSame(mp1.Get("one"),mp2.Get("one"))) Then
..

Here ConvertObjectToBytes will generate the same sequence for both maps. This is because Key "one" doesn't exist in map2 leading to an arry representing Null, the same array generated for the regular value Null returned by the Get on map1.

Well, now that my couriosity is satisfied I can get ready for my long walk (weather is very nice today)..
 
Upvote 0

cklester

Well-Known Member
Licensed User
So, after @udg 's suggestion, this slight modification:

B4X:
Private Sub isSame(a As Object, b As Object) As Boolean
    Dim ser As B4XSerializator
    Dim ab() As Byte = ser.ConvertObjectToBytes(a)
    Dim bb() As Byte = ser.ConvertObjectToBytes(b)
    For i = 0 To ab.Length - 1
        If ab(i) <> bb(i) Then Return False
    Next
    Return True
End Sub

Sub MapsAreEqual(mp1 As Map ,mp2 As Map) As Boolean
    If mp1.Size <> mp2.Size Then Return False
    For Each Key As Object In mp1.Keys
        If mp1.Get(Key) Is Map Then
            If mp2.Get(Key) Is Map Then
                If MapsAreEqual(mp1.Get(Key),mp2.Get(Key)) = False Then
                    Return False
                End If
            Else
                Return False
            End If
        Else
            If mp2.Get(Key) Is Map Then Return False
            If mp1.Get(Key) = Null Or mp2.Get(Key) = Null Then Return False 'fail if null found anywhere... sorry
            If Not(isSame(mp1.Get(Key),mp2.Get(Key))) Then
                Return False
            End If
        End If
    Next
    Return True
End Sub

Can anybody find a breaking case, again? ?
 
Upvote 0

cklester

Well-Known Member
Licensed User
Maybe it is out of scope of what you want to do, but if the value of a map is a Class or a Type, it may fail (e.g. if a property of this class is a map).

Good point. This endeavor to find equality in two maps might ever be futile except for specific use-cases. The one I'm using it for is a simple case where I know what will be compared.
 
Upvote 0

rabbitBUSH

Well-Known Member
Licensed User
The one I'm using it for is a simple case where I know what will be compared.
I wondered along the way, and that sentence part brought the question....maybe I lost the thread of things.

What is the intention of this? Another dumbo one.

Seems at least three things...which could be independent intentions.

1. a[ i]==b[ i] looping finds where each position in each 'column ' is the same.
2. a[ i]==b[0..n] should be: find where a exists somewhere in b[0..n].
3. I suppose there is a case where 1 and 2 can be combined : where are the equal ones and / or how many cases of a are there in b, and, logically, where are those.

Just trying to keep up.
 
Last edited:
Upvote 0

DonManfred

Expert
Licensed User
Longtime User
To save changes when a change is detected.
Can you not just store the map serialized? Does not take much time to save a map to a file.
 
Upvote 0

cklester

Well-Known Member
Licensed User
Can you not just store the map serialized? Does not take much time to save a map to a file.

Yes, I'm saving it serialized, but I'm trying to save a trip to the server if no change has been made to the data. There are other ways to track changes, but this way (compare the current map to the last map) seems like the easiest way since the size of the data set is so small.

I'm open to suggestions!
 
Upvote 0

OliverA

Expert
Licensed User
Longtime User
I'm open to suggestions
Add a dirty flag to the map? Anytime an update is done to the map, the dirty flag is set to true. If it is synced to the server, set dirty flag to false. (Sort of like the Archive bit in the file system used for backups)
 
Upvote 0

cklester

Well-Known Member
Licensed User
Add a dirty flag to the map? Anytime an update is done to the map, the dirty flag is set to true. If it is synced to the server, set dirty flag to false. (Sort of like the Archive bit in the file system used for backups)

OK, so I had thought of doing that, but here's where I stopped thinking about it: If I make a change to the map, the dirty_map flag is set to True. Easy. However, let's say I make other changes, but then decide to go back and change one of those values back to what it was before. I have to track all the original values of the map and always check to see if the user reset a particular value back to the original value after a prior change to that value.

It's probably a very easy thing to program, but I've gone with the brute force method because of laziness.

Is one way more efficient than the other?
  1. Check for a change to the original map prior to syncing with server
  2. Keep a change_flag updated while the user is running the app, then sync with server if set to True
What do you think?
 
Upvote 0

Daestrum

Expert
Licensed User
Longtime User
I have to track all the original values of the map and always check to see if the user reset a particular value back to the original value after a prior change to that value.
Why? Surely you just want the latest data that is in the (Users) map, it makes no difference if the user changes something then changes it back. If the user changes something then resync to server, the copy on the server will then be a copy of the latest one held on the users device.
 
Upvote 0

cklester

Well-Known Member
Licensed User
Why? Surely you just want the latest data that is in the (Users) map, it makes no difference if the user changes something then changes it back. If the user changes something then resync to server, the copy on the server will then be a copy of the latest one held on the users device.

True, but I wanted to avoid hitting the server that often. So, what happens now is, I wait until they close the data screen before checking if there's a need to sync. If there's a change, sync it. If not, no sync.

I might just need to do some performance testing to see what kind of hit each approach takes.
 
Upvote 0
Top