Android Example How to sort a Map

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

Tags:
  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:
    Code:
    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
        SortList1.Initialize
        SortList1.clear
        
    For i = 0 To inMap1.Size-1
          
    Dim p As SortHulp1
          p.Key1 = inMap1.GetKeyAt(i)
          p.Val1 = inMap1.GetValueAt(i)
          SortList1.Add(p)
        
    Next
        SortList1.SortType(Sort1, 
    True)         'Sort the list based on the desired field.
        inMap1.Clear
        
    For i = 0 To SortList1.Size-1
          
    Dim p As SortHulp1
          p = SortList1.Get(i)
          inMap1.Put(p.Key1,p.Val1)
        
    Next
        
    Return inMap1
    End Sub
    Usage example in which MyMap1 is an existing Map that requires sorting (by key or by value):
    Code:
    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...!
    OK.
    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 at 11:49 AM
  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 :(]

    Code:
    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

    Code:
    ' 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:
    ' SORTMAP_FIELD_KEY or SORTMAP_FIELD_VALUE.
    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
       lstSort.Initialize
     
       
    For i = 0 To MapToSort.Size - 1
           
    Dim Item As tMapItem
           Item.Key = MapToSort.GetKeyAt(i)
           Item.Value = MapToSort.GetValueAt(i)
           lstSort.Add(Item)
       
    Next
     
       
    If CaseInsensitive Then
           lstSort.SortTypeCaseInsensitive(SortField, Ascending)
       
    Else
           lstSort.SortType(SortField, Ascending)
       
    End If

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

    ' Test (strings only):
    Code:
    Sub Activity_Create(FirstTime As Boolean)
       
    Dim mapStrings As Map
       mapStrings.Initialize
     
       
    For i = 1 To 20
           mapStrings.Put(i, 
    Chr(Rnd(6591)))
       
    Next
     
       mapStrings = SortMap(mapStrings, SORTMAP_FIELD_VALUE, 
    FalseTrue)
     
       
    For Each Key As Int In mapStrings.Keys
           
    Log(Key & TAB & mapStrings.Get(Key))
       
    Next
    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 at 2:59 PM
  8. LucaMs

    LucaMs Expert Licensed User

    Tested: does not work :mad::eek:

    Code:
    Sub Process_Globals
    '...
    Type tObject(ID As Int, Name As String, Capital As Double)
    Code:
    Private Sub SecondTest
       
    Dim mapObjects As Map
       mapObjects.Initialize
      
       
    Dim lstNames As List
       lstNames.Initialize2(
    Array As String("Erel""Klaus""Mario""Penelope""Cameron", _
                                                        
    "Kate""June""Juliet""Susan""Mandy"))
       
    For i = 1 To 10
           
    Dim MyObject As tObject
           MyObject.Initialize
           
    Dim ID As Int = Rnd(1101)
           MyObject.ID = 
    ID
           MyObject.Name = lstNames.Get(i - 
    1)
           MyObject.Capital = 
    Rnd(100100000) / 100
           mapObjects.Put(
    ID, MyObject)
       
    Next
      
       mapObjects = SortMap(mapObjects, SORTMAP_FIELD_VALUE, 
    FalseTrue)
      
       
    Log("objects test" & CRLF)
       
    For Each Key As Int In mapObjects.Keys
           
    Log(Key & TAB & mapObjects.Get(Key))
       
    Next
      
    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 at 7:44 AM
  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 at 7:41 AM
  14. LucaMs

    LucaMs Expert Licensed User


    Does "anyone" have the solution? :)
     
Loading...