Android Example How to sort a Map

Discussion in 'Tutorials & Examples' started by Syd Wright, May 13, 2018.

  1. Syd Wright

    Syd Wright Active Member Licensed User

    I searched the Forum regarding how to sort a Map but could not find anything.
    Here is my solution:
    Sub Globals
    Type SortHulp1(Key1 As String, Val1 As String)
    End Sub

    Sub SORT_MAP1(inMap1 As Map, Sort1 As StringAs Map    'inMap is the Map that needs to be sorted; Sort1 is "Key1" or "Val1"
        If Sort1<>"Key1" And Sort1<>"Val1" Then Return Null
    Dim SortList1 As List
    For i = 0 To inMap1.Size-1
    Dim p As SortHulp1
          p.Key1 = inMap1.GetKeyAt(i)
          p.Val1 = inMap1.GetValueAt(i)
    True)         'Sort the list based on the desired field.
    For i = 0 To SortList1.Size-1
    Dim p As SortHulp1
          p = SortList1.Get(i)
    Return inMap1
    End Sub
    Usage example in which MyMap1 is an existing Map that requires sorting (by key or by value):
    MyMap1 = SORT_MAP1(MyMap1,"Key1"'or: 
    MyMap1 = SORT_MAP1(MyMap1,"Val1")
    LucaMs likes this.
  2. LucaMs

    LucaMs Expert Licensed User

    Do not forget that maps can contain any type of object, both as keys and as values.

    Work your variables of type SortHulp1 (strange name) although you did not initialize them?

    SortList1.Clear immediately after SortList1.Initialize is not needed.

    You could use two public constants instead of "key1" and "val1".
  3. Syd Wright

    Syd Wright Active Member Licensed User

    I am Dutch...!
    SortHulp1 is a Type and created under Globals; inMap indeed does not need to be initialized. I also initially thought that this would be necessary. I assume that the original Map is used and that "inMap" in the sub is just a temporary name to the object: The input Map is not first copied to a new map called inMap.
    I hear what you say, but this will complicate matters substantialy. The Maps that I use nearly always use strings for the Key and the Value. Feel free to improve my Android Example and share it with everyone. I am curious how you will make it universal for any kind of object. Sorting simply won't work nor will it ever be used for many objects...
    Last edited: May 14, 2018
  4. LucaMs

    LucaMs Expert Licensed User

    I'm sorry for you.
    Just kidding, of course, I'm italian! ;)
    I would not have even used the number 1, especially this I meant.

    SortHulp1 should be declared in Process_Globals and variables of this type should be initialized. Parameters must be never initialized.

    I could be wrong, of course, but in many cases this would also work well with objects (depending on the type and complexity of the object).
    Soon I will try to modify your code and add it here.

    Thank you for sharing!!!
  5. DonManfred

    DonManfred Expert Licensed User

    not really... I can imagine the Author is from the Netherlands so SortHulp is probably Dutch and means something like SortHelp....
  6. LucaMs

    LucaMs Expert Licensed User

    I'm almost sure of this (like SortHilfe ;)) but I would not even chosen SortHelp1, Key1, Val1... why those "1"?
  7. LucaMs

    LucaMs Expert Licensed User

    [Not tested well and, mainly, not tested with a map of objects - Do not forget I'm lazy :p and that I'm late for years :(]

    Sub Process_Globals
    Type tMapItem(Key As Object, Value As Object)
    Public Const SORTMAP_FIELD_KEY As String = "Key"
    Public Const SORTMAP_FIELD_VALUE As String = "Value"
    End Sub

    ' Sorts a Map based on the SortField you chose,
    ' the keys of the Map or the values of the Map.
    ' SortField: pass one of the two constants provided:
    Public Sub SortMap(MapToSort As Map, SortField As String, CaseInsensitive As Boolean, Ascending As Boolean) As Map    'inMap is the Map that needs to be sorted; Sort1 is "Key1" or "Val1"
       If SortField <> SORTMAP_FIELD_KEY And SortField <> SORTMAP_FIELD_VALUE Then Return Null
    Dim lstSort As List
    For i = 0 To MapToSort.Size - 1
    Dim Item As tMapItem
           Item.Key = MapToSort.GetKeyAt(i)
           Item.Value = MapToSort.GetValueAt(i)
    If CaseInsensitive Then
           lstSort.SortTypeCaseInsensitive(SortField, Ascending)
           lstSort.SortType(SortField, Ascending)
    End If

    For i = 0 To lstSort.Size - 1
    Dim Item As tMapItem
           Item = lstSort.Get(i)
           MapToSort.Put(Item.Key, Item.Value)
    Return MapToSort
    End Sub

    ' Test (strings only):
    Sub Activity_Create(FirstTime As Boolean)
    Dim mapStrings As Map
    For i = 1 To 20
       mapStrings = SortMap(mapStrings, SORTMAP_FIELD_VALUE, 
    For Each Key As Int In mapStrings.Keys
    Log(Key & TAB & mapStrings.Get(Key))
    End Sub

    [The two constants are useful so you don't need to check if the user writes "key" or "KEY" or "kEy"... Also, providing constants for parameters is a good practice]
    Last edited: May 14, 2018
  8. LucaMs

    LucaMs Expert Licensed User

    Tested: does not work :mad::eek:

    Sub Process_Globals
    Type tObject(ID As Int, Name As String, Capital As Double)
    Private Sub SecondTest
    Dim mapObjects As Map
    Dim lstNames As List
    Array As String("Erel""Klaus""Mario""Penelope""Cameron", _
    For i = 1 To 10
    Dim MyObject As tObject
    Dim ID As Int = Rnd(1101)
           MyObject.ID = 
           MyObject.Name = lstNames.Get(i - 
           MyObject.Capital = 
    Rnd(100100000) / 100
    ID, MyObject)
       mapObjects = SortMap(mapObjects, SORTMAP_FIELD_VALUE, 
    Log("objects test" & CRLF)
    For Each Key As Int In mapObjects.Keys
    Log(Key & TAB & mapObjects.Get(Key))
    End Sub
    Error occurred on line: 100 (Main) [100 lstSort.SortType(SortField, Ascending)]
    java.lang.RuntimeException: java.lang.ClassCastException: b4a.example.main$_tobject cannot be cast to java.lang.Comparable
  9. Syd Wright

    Syd Wright Active Member Licensed User

    Pity that it doesn't work, but keep trying! :) At least my version in thread #1 does work fine for strings.
    Good idea to use constants. I can't see where the cause of the java error is.
    Yes "SortHulp" (Dutch) can best be translated to "Sorting Aid".
    I often use numbered objects, like Dhulp1, Dhulp2 etc. My (self-taught) programming experience goes back about 40 years (to the time of the Zilog Z80 processor), so over the years many personal particularities (and quicks) pop up...
    LucaMs likes this.
  10. LucaMs

    LucaMs Expert Licensed User

    With string even my version SEEMS to work.

    You could add to yours these two parameters:
  11. LucaMs

    LucaMs Expert Licensed User

    I'm working on another little project (to be shared), now, and it also works... badly :p (for the moment, I hope).
    Last edited: May 15, 2018
  12. Syd Wright

    Syd Wright Active Member Licensed User

    OK, looks promissing. I tried your second test a moment ago and get the same java error.
    Maybe converting input integers, longs, doubles etc. to a string before sorting (and reverse this after sorting) is a simple solution to use my original code. But ofcourse without using such a trick would be better.

    By the way, the sorting has its own particularities. For example I tried to sort a list with times as the key:
    for example 21:34, 7:15, 9:55, 15:10, 22:00, 6:40 and 23:36. Not only did I have to remove the ":" but also had to add a "0" in front of the times before 12:00 otherwise the sort result would be wrong!
  13. LucaMs

    LucaMs Expert Licensed User

    Yes, when sorting numbers as strings they must been of the same length.
    Last edited: May 15, 2018
  14. LucaMs

    LucaMs Expert Licensed User

    Does "anyone" have the solution? :)
  15. Diceman

    Diceman Member Licensed User

    I don't believe sorting maps will work because you cannot be assured of traversing the map in any particular (consistent) order. You have to assume the order of the map is non-sequential (different from the order they were inserted) because the physical location of the rows in a map is determined internally by the Map class. The best you could hope for is to put the map keys into a List then sort the list. After the List has been sorted, you need to traverse the List and for each item in the list, get the value from the map. So if you have a map with 1000 entries in it, the List will have 1000 entries and in the loop for the list, you will look up the map values 1000 times. This will be quite slow for large maps.
  16. LucaMs

    LucaMs Expert Licensed User

    The code in #7 works and you get ordered maps; the "only" "little" problem is that it is created to sort objects but it seems to work only with simple data types (strings, numbers).
  17. Diceman

    Diceman Member Licensed User

    I don't think you can depend on being able to traverse the map and expect it to return the rows in the same order they were added.

    You are executing
    MapToSort.Put(Item.Key, Item.Value)​

    to put physically put the map into sorted order. But it doesn't guarantee the rows will stay in the same order as they were added. It may work 95% of the time.
    It is like adding rows to a database table in sorted order and then using SQL "Select * from table" without an Order By clause because you are depending on the insert order to always retrieve the rows in the correct order.

    You may need to confirm with with Erel if you need it sorted properly 100% of the time.
    LucaMs likes this.
  18. Erel

    Erel Administrator Staff Member Licensed User

    GetKeyAt / GetValueAt should never be used. It is explained in the video tutorial about collections.
    You should use For Each instead.

    I haven't followed the other posts. Sorry.
  19. LucaMs

    LucaMs Expert Licensed User

    You should :p
  20. Diceman

    Diceman Member Licensed User

    Is it possible to sort a map and traverse the map in sorted order (reliably)?
    Or is it better to copy the map to a List, sort the list and traverse the List in sorted order?
  1. This site uses cookies to help personalise content, tailor your experience and to keep you logged in if you register.
    By continuing to use this site, you are consenting to our use of cookies.
    Dismiss Notice