Sebastian Zdroana Sebastian Zdroana - 5 months ago 20
Android Question

How can I sort an ArrayList<HashMap<Integer, Boolean>>?

In my MainActivity.java I have:

public static ArrayList<HashMap<Integer,Boolean>> booleanArrayList = new ArrayList<>();

public static void setBooleanArrayList(int p, Boolean b){
HashMap<Integer,Boolean> map = new HashMap<>();
map.put(p, b);
booleanArrayList.add(map);
}
public static HashMap<Integer, Boolean> getBooleanArrayList(int position){
return booleanArrayList.get(position);
}


I have a fragment which has a button. When the button is clicked I want it to sort MainActivity.booleanArrayList in ascending order.

For example:

{1,true}
{4,true}
{2,false}
{3,true}


sorted:

{1=true}
{2=false}
{3=true}
{4=true}


How would I go about sorting the ArrayList> once it is populated?

Answer Source

There are 2 steps in doing that. First, write a Comparator that will compare 2 Maps:

public class MapKeyComparator implements Comparator<Map<Integer, Boolean>> {

        @Override
        public int compare(Map<Integer, Boolean> me, Map<Integer, Boolean> him) {
            Set<Integer> meSet = me.keySet();
            Set<Integer> himSet = him.keySet();
            // Sanity check
            if(me.size() != 1 || himSet.size() != 1){
                throw new RuntimeException("Comparison can only be done between 2 valid integers.");
            }
            // Values
            int meI = 0, himI = 0;
            for(Integer i : meSet){
                meI = i;
            }
            for(Integer i : himSet){
                himI = i;
            }
            // Compare
            if(meI > himI){
                return -1;
            }
            else if(meI < himI){
                return 1;
            }
            else{
                return 0;
            }
        }
    }

And then, sort the list like below:

Collections.sort(booleanArrayList, new MapKeyComparator());

Explanation:

Well, a Comparator is an interface that you can implement to compare 2 objects, say Integers. It can be any object in general but think about it, since it is comparison, it should make sense too comparing them. For ex, you wouldn't compare Bird object with a Tree. You can compare one Bird type with that of another because they have attributes that you can compare.

Now, in your case, we had to compare the Keys of the Maps present in the ArrayList. That means, the object to compare is a Map but based on what?

Well, you already know that - the Key of the Map. And, Comparator is an interface that facilitates just that.

So, we shall build a Comparator for comparing 2 Maps based on each Map's key. This Comparator in turn shall be used by the Collections.sort() method which takes a list of objects to compare and a Comparator to compare them.

Before we build the Comparator, lets see what the Docs have to say about a Comparator.

public interface Comparator<T>

A comparison function, which imposes a total ordering on some collection of objects. Comparators can be passed to a sort method (such as Collections.sort or Arrays.sort) to allow precise control over the sort order. Comparators can also be used to control the order of certain data structures (such as sorted sets or sorted maps), or to provide an ordering for collections of objects that don't have a natural ordering.

And about the method you have to implement,

int compare(T o1, T o2)

Parameters:

o1 - the first object to be compared. o2 - the second object to be compared.

Returns: a negative integer, zero, or a positive integer as the first argument is less than, equal to, or greater than the second.

Notice that it says to return 1 if first object is greater than second. But I did the reverse in the implementation so that you can get a ascending arrangement instead of a descending one in Collections.sort().

The implementation:

The implementation itself it pretty straightforward. Since I have to compare the keys from the Maps, I retrieve the keys in a Set:

Set<Integer> meSet = me.keySet();
Set<Integer> himSet = him.keySet();

Next, I check if they have a single element so that the comparison actually makes sense:

// Sanity check
if (me.size() != 1 && himSet.size() != 1) {
    throw new RuntimeException("Comparison can only be done between 2 valid integers.");
}

Next, I iterate the sets to get the one element present in both of them:

// Values
int meI = 0, himI = 0;
for (Integer i: meSet) {
    meI = i;
}
for (Integer i: himSet) {
    himI = i;
}

Next, we actually compare them,

// Compare
if (meI > himI) {
    return -1;
} else if (meI < himI) {
    return 1;
} else {
    return 0;
}

Also, see the docs for Collections.sort() method.


Having said all that, there are other(better) things you can do for your basic problem like using a TreeMap which arranges the elements when you insert with the natural ordering. So when you retrieve them, you get them in the order you had always wanted. @ravi-koradia 's advice is spot on in terms of that and this article does a great job of explaining it:

https://dzone.com/articles/hashmap-vs-treemap-vs