sorting a List of MapString, String
The following code works perfectly
public Comparator<Map<String, String>> mapComparator = new Comparator<Map<String, String>>() {
public int compare(Map<String, String> m1, Map<String, String> m2) {
return m1.get("name").compareTo(m2.get("name"));
}
}
Collections.sort(list, mapComparator);
But your maps should probably be instances of a specific class.
Sort ListMapString,Object based on value
You can generalize comparing numbers by comparing their double values, because they are the largest. If two objects cannot be cast to numbers and the double value cannot be parsed from these objects, then compare their string values:
List<Map<String, Object>> data = Arrays.asList(
Map.of("Field1", 21.2d), // Double
Map.of("Field1", "qqq"), // String
Map.of("Field1", "22.5"), // String
Map.of("Field1", 2), // Integer
Map.of("Field1", 3L), // Long
Map.of("Field1", 23.1f)); // Float
data.sort(Comparator.comparingDouble((Map<String, Object> map) -> {
Object object = map.get("Field1");
if (object instanceof Number) {
return ((Number) object).doubleValue();
} else {
try {
return Double.parseDouble(String.valueOf(object));
} catch (NumberFormatException e) {
return Double.NaN;
}
}
}).thenComparing(map -> String.valueOf(map.get("Field1"))));
data.forEach(System.out::println);
// {Field1=2}
// {Field1=3}
// {Field1=21.2}
// {Field1=22.5}
// {Field1=23.1}
// {Field1=qqq}
See also: Sort 2D List by Column Header
How can I sort a MapString, ListCustomObject?
By changing the type of Map
used in my code above, as suggested by @Thomas, in TreeMap<>
, I found the solution to the problem as follows:
- I first merged all the
Person
object lists into one list. This was then sorted by the chosen criterion, for examplePerson.COMPARE_BY_NAME
; - I created an algorithm that would re-group the sorted lists, in according to the criteria of my project, in a map. The key of this map corresponds to the concatenation of the month + year of the
Person
object.
The algorithm is reported at the bottom of the comment; - I sort the map based on the chosen attribute, for example
Sorter.COMPARATOR_BY_NAME
;
Di seguito il codice è come segue:
Merge all List<Person>
in one -> main or somewhere before the Map was created
...
//
List<Person> newPersonList = new ArrayList<>();
newPersonList.addAll(oldPersonList1);
newPersonList.addAll(oldPersonList2);
...
Main or somewhere before the Map was created
...
groupList(Person.COMPARE_BY_NAME, Sorter.COMPARATOR_BY_NAME);
...
GroupPerson -> method to group the merged List<Person>
in a TreeMap<String, List<Person>>
public Map<String, List<Person>> groupList(final Comparator<? super Person> itemComparator, final Comparator<? super List<Person>> listComparator)
// Sort Person list by comparator before create TreeSet
newPersonList.sort(itemComparator);
Map<String, List<Person>> personMapGrouped = new TreeMap<>();
// Here, create a Map of list
for (Person person: newPersonList) {
final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy MM", Locale.getDefault());
final String groupKey = dateFormat.format(person.getDateOfBirth());
if (personMapGrouped.containsKey(groupKey)) {
// The key is already in the TreeMap; add the Person object against the existing key.
final List<Person> personListGrouped = personMapGrouped.get(groupKey);
if (personListGrouped!= null) {
personListGrouped.add(person);
}
} else {
// The key is not there in the TreeMap; create a new key-value pair
final List<Person> personListGrouped = new ArrayList<>();
personListGrouped.add(person);
personMapGrouped.put(groupKey, personListGrouped);
}
}
// Here sort the Map by params passed
final TabPersonSorter sorter = new TabPersonSorter();
personMapGrouped = sorter.sort(personMapGrouped, listComparator);
}
In this case, using the lists created in the main above, the results obtained are:
"List<Person> mergedList": [
Person("name1", new Date("2022-01-01")),
Person("name3", new Date("2021-02-05")),
Person("name4", new Date("2021-02-03")),
Person("name12", new Date("2022-01-05")),
Person("name13", new Date("2022-01-03")),
Person("name14", new Date("2021-02-01"))
]
"Map<String, List<Person>> mergedMap": {
"2022-01": [
Person("name1", new Date("2022-01-01")),
Person("name12", new Date("2022-01-05")),
Person("name13", new Date("2022-01-03"))
],
"2021-02": [
Person("name3", new Date("2021-02-05")),
Person("name4", new Date("2021-02-03"))
],
"2022-02": [
Person("name14", new Date("2021-02-01"))
]
}
Obviously if the grouping in the map were not bound by such a restrictive date as only year + month, the sorting would have the desired effect in distinct groups.
In fact, in the case of the sorting by date, this is respected very well.
Sorting a list of MapString, String based on a particular numeric value
If is not possible to create a class from that map then you can do something like:
Collections.sort(foo, (o1, o2) -> {
return new BigDecimal(o2.get("score")).compareTo(new BigDecimal(o1.get("score")));
});
or if you are not using java 8:
Collections.sort(foo, new Comparator<Map<String, String>>() {
@Override
public int compare(Map<String, String> o1, Map<String, String> o2) {
return new BigDecimal(o2.get("score")).compareTo(new BigDecimal(o1.get("score")));
}
});
How to sort ListMapString,String by key1 descending order and key2 ascending order if key1 has same values
It's easier if you build your Comparator
in two steps. So try this and print them out. It works like this.
- first it sorts the price in reversed order.
- Then t sorts the product number in regular order for equal prices.
Comparator<Map<String, String>> comp = Comparator
.comparing(m ->Double.parseDouble(m.get("price"))
,Comparator.reverseOrder());
comp = comp.thenComparing(m -> m.get("productNumber"));
Apply it like so.
List<Map<String, String>> formattedResult =
list.stream().sorted(comp)
.collect(Collectors.toList());
formattedResult.forEach(m -> System.out.println(
m.get("price") + " : " + m.get("productNumber")));
This prints
1.99 : 107-001
1.99 : 109-001
1.02 : 108-001
Sort a list of maps based on two values
You could implement a custom Comparator
based on those two values:
list.sort(Comparator.comparing((Map<String, Object> map) -> (Integer) map.get("Age"))
.thenComparing((Map<String, Object> map) -> (String) map.get("Name"))
);
Sort ListMapString, Object by a particular key in the map
Since JAVA 1.8 there is new method in java.util.Comparator called comparing.
It returns comparator comparing objects by given key.
https://docs.oracle.com/javase/8/docs/api/java/util/Comparator.html#comparing-java.util.function.Function-
In this case to compare by names it would look like:
list.sort(Comparator.comparing(o -> String.valueOf(o.get("name"))));
and to compare by id:
list.sort(Comparator.comparing(o -> (Long) o.get("id")));
How to i sort a ListMapString,Object in java
You can use a custom comparator, but you need your values (currently Object
) to implement Comparable
. Based on the current declaration of your list, you can't do it (how do you compare two random objects?):
List<Map<String,Comparable>> listMap = ...
Collections.sort(listMap, new Comparator<Map<String, Comparable>> () {
@Override
public int compare(Map<String, Comparable> m1, Map<String, Comparable> m2) {
return m2.get("full_inc").compareTo(m1.get("full_inc")); //descending
}
});
Note: you need to add error checking.
Sort the values in a map of type MapString, ListString
Since list you want to sort can contain null
and you can't call compareTo
on null
(since it doesn't have any methods nor fields) you will need to provide your own Comparator which will handle null
and use it with sorting method.
For instance if you would like to place null
at end of ascending order you will need to implement rules like:
null
null
- don't swap, there is no point (return 0)null
"someString"
- swap, null is bigger and should be placed after"someString"
(return 1)"someString"
null
- don't swap, first argument ("someString"
) is smaller thannull
(return -1)"string1"
"string2"
- return default result of comparing both non-null values
and your Comparator can look like
Comparator<String> myComparator = new Comparator<String>() {
@Override
public int compare(String s1, String s2) {
if (s1==null && s2==null) return 0;//swapping has no point here
if (s1==null) return 1;
if (s2==null) return -1;
return s1.compareTo(s2);
}
};
Now you can use it
for (List<String> list : yourMap.values()) {
Collections.sort(list, myComparator);
}
Java 8 update
Since Java 8 Comparator
provides methods which can wrap other comparator and create another one which will place nulls at start or end of our collection. This methods are:
Comparator.nullsFirst(Comparator)
Comparator.nullsLast(Comparator)
Also sort(Comparator)
method was added to List
interface which means we don't need to call explicitly Collections.sort(list,comparator)
.
So your code can look like:
for (List<String> list : yourMap.values()) {
list.sort(Comparator.nullsLast(Comparator.naturalOrder()));
}
But nothing stops you from using other comparator instead of Comparator.naturalOrder()
like one stored in String.CASE_INSENSITIVE_ORDER
which now can also be created with String::compareToIgnoreCase
method reference.
Related Topics
How to Convert Rgb Color to Int in Java
How to Delete Files Programmatically on Android
Why Menuitemcompat.Getactionprovider Returns Null
Open Source Face Recognition for Android
Enabling Specific Ssl Protocols with Android Webviewclient
How to Do a Cross Platform Encryption Method Working in Both iOS and Android (Aes Encryption Only..)
Stack Overflows from Deep Recursion in Java
How to Find How Much Disk Space Is Left Using Java
How to Resume Android Activity Programmatically from Background
Fragment Add or Replace Not Working
Android Proguard, Keep Inner Class
Android - Get Value from Hashmap
Get Button Coordinates and Detect If Finger Is Over Them - Android
What Is the Equivalent of a Java Hashmap<String,Integer> in Swift