I have an ArrayList of HashMap. Each HashMap contains many key-value-pairs. I want to sort the ArrayList by the value of the key distance in the HashMap.
ArrayList<HashMap<String, String>> arrayListHashMap =
new ArrayList<HashMap<String, String>>();
{
HashMap hashMap = new HashMap<String, Object>();
hashMap.put("key", "A key");
hashMap.put("value", "B value");
hashMap.put("distance", 2536);
arrayListHashMap.add(hashMap);
}
{
HashMap hashMap = new HashMap<String, String>();
hashMap.put("key", "B key");
hashMap.put("value", "A value");
hashMap.put("distance", 2539);
arrayListHashMap.add(hashMap);
}
Add all the HashMaps to a list and sort it using a custom Comparator like this:
Collections.sort(arrayListHashMap, new Comparator<HashMap<String, Object>>() {
#Override
public int compare(HashMap<String, Object> o1, HashMap<String, Object> o2) {
return ((Integer) o1.get("distance")).compareTo(
(Integer) o2.get("distance"));
}
});
Full example:
public static void main(String... args) {
List<HashMap<String, Object>> arrayListHashMap =
new ArrayList<HashMap<String, Object>>();
{
HashMap<String, Object> hashMap = new HashMap<String, Object>();
hashMap.put("key", "A key");
hashMap.put("value", "B value");
hashMap.put("distance", 2536);
arrayListHashMap.add(hashMap);
}
{
HashMap<String, Object> hashMap = new HashMap<String, Object>();
hashMap.put("key", "B key");
hashMap.put("value", "A value");
hashMap.put("distance", 2539);
arrayListHashMap.add(hashMap);
}
Collections.sort(arrayListHashMap,
new Comparator<HashMap<String, Object>>() {
#Override
public int compare(
HashMap<String, Object> o1,
HashMap<String, Object> o2) {
return ((Integer) o1.get("distance")).compareTo(
(Integer) o2.get("distance"));
}
});
System.out.println(arrayListHashMap);
}
You can try to sort with a custom comparator:
Collections.sort(arrayListHashMap, new Comparator<HashMap<String, String>>() {
#Override
public int compare(HashMap<String, String> m1, HashMap<String, String> m2) {
return Integer.valueOf(m1.get("distance")).compareTo(Integer.valueOf(m2.get("distance")));
}
});
Note that I assumed all your values are strings which is not the case in your example (distance is an int value).
Related
There is a hashmap and below is the requirement :
Map<String, Object> objectmetainfo = new HashMap();
objectmetainfo.put("userdetails.info.metadata.user.home.address.details", "address");
objectmetainfo.put("userdetails.info.metadata.user.id", "id");
objectmetainfo.put("userdetails.info.metadata.userSupervisor.id", "id");
objectmetainfo.put("info.metadata.code", "code");
objectmetainfo.put("zip", "zip");
Get all the records of hashmap and iterate it
Split the Key based on delimiter and convert it to Pair or Hashmap
The number of delimiter will vary in each string
Below should be the output :
E.g.: For "userdetails.info.metadata.user.home.address.details", "address", below output is required
HashMap<userdetails, HashMap<info, HashMap<metadata, HashMap<user, HashMap<home, HashMap<address, Map<details, address>>>>>>>
or Pair<String, Object> pair = new Pair("userdetails", new Pair("info", new Pair("metadata", new Pair("user", new Pair("home", new Pair("address", new Pair("details", "addressvalue")))))));
Assuming your string won't be crazy long this would work, otherwise you'd get a StackOverflow error.l
I did this using a recursive approach
Split keys by "."
Convert them to the list iterator
Iterate this list recursively to create a nested map
At the end of recursion put the value from objectmetainfo map.
Create an empty result map and recursively merge all the results.
Code:
import java.util.*;
public Map<String, Object> nestedMaps(Iterator<String> keys, String value) {
if (keys.hasNext()) {
String key = keys.next();
Map<String, Object> nestMap = nestedMaps(keys, value);
Map<String, Object> map = new HashMap<>();
map.put(key, nestMap);
if (Objects.equals(nestMap, null))
map.put(key, value);
return map;
}
return null;
}
public void mergeNested(Object srcObj, Object targetObj) {
if (srcObj instanceof Map && targetObj instanceof Map) {
Map<String, Object> srcMap = (Map<String, Object>) srcObj;
Map<String, Object> targetMap = (Map<String, Object>) targetObj;
for (String targetKey : targetMap.keySet()) {
if (srcMap.containsKey(targetKey)) {
mergeNested(srcMap.get(targetKey), targetMap.get(targetKey));
} else {
srcMap.putAll(targetMap);
}
}
}
}
public Map<String, Object> objectmetainfo = new LinkedHashMap<>();
objectmetainfo.put("userdetails.info.metadata.user.home.address.details", "addressValue");
objectmetainfo.put("userdetails.info.metadata.user.id", "id");
objectmetainfo.put("userdetails.info.metadata.userSupervisor.id", "id");
objectmetainfo.put("info.metadata.code", "code");
objectmetainfo.put("zip", "zip");
public Map<String, Object> result = new HashMap<>();
for (Map.Entry<String, Object> e : objectmetainfo.entrySet()) {
List<String> keys = new ArrayList<>(Arrays.asList(e.getKey().split("\\.")));
Map<String, Object> nestedMaps = nestedMaps(keys.iterator(), String.valueOf(e.getValue()));
mergeNested(result, nestedMaps);
}
System.out.println(result);
I printed out all the hashmaps using toString method.
Output:
{
zip= zip,
userdetails= {
info= {
metadata= {
userSupervisor= {
id= id
},
user= {
id= id,
home= {
address= {
details= addressValue
}
}
}
}
}
},
info= {
metadata= {
code= code
}
}
}
Below is the modified logic to remove 2nd recursive call, with this method we are passing the objMap as reference and finally we will have the objMap ready with result
Map<String, Object> objMap = new HashMap<>();
for (Map.Entry<String, Object> e : getObjectMetaInfoMap().entrySet()) {
populateMetaDataMap(keys.iterator(), String.valueOf(e.getValue()), objMap, true, StringUtils.EMPTY);
}
public static Map<String, Object> populateMetaDataMap(Iterator<String> keys, String value, Map<String, Object> objMap, boolean newCall, String matchingKey) {
if (keys.hasNext()) {
String key = keys.next();
if(objMap.get(key) != null && objMap.get(key) instanceof Map) {
return populateMetaDataMap(keys, value, (Map<String, Object>) objMap.get(key), newCall, matchingKey );
} else {
if(newCall) {
newCall = false;
matchingKey = key;
}
Map<String, Object> nestMap = populateMetaDataMap(keys, value, objMap, newCall, matchingKey);
Map<String, Object> map = new HashMap<>();
if (Objects.equals(nestMap, null))
map.put(key, value);
else
map.put(key, nestMap);
if(key.equals(matchingKey)) {
if(Objects.equals(nestMap, null)) {
objMap.put(key, value);
} else {
objMap.put(key, nestMap);
}
}
return map;
}
}
return null;
}
How can I filter map of map using java stream. I can do it using double loop but I think this is not efficient.
public class MapUsage {
static Map<Integer, Map<Integer, String>> parentMap = new HashMap<>();
static Map<String, String> userRole = new HashMap<>();
public static void main(String ... args){
initializeData();
displayMapForUser("user1", parentMap);
// printMap(parentMap);
}
private static void displayMapForUser(String user1, Map<Integer, Map<Integer, String>> parentMap) {
Integer role = new Integer(userRole.get(user1));
Map<Integer, Map<Integer, String>> userMap = new HashMap<>();
Map<Integer, String> childMap = new HashMap<>();
for(Map.Entry<Integer, Map<Integer, String >> entry : parentMap.entrySet()){
for(Map.Entry<Integer, String > entry1: entry.getValue().entrySet()){
if(entry1.getKey().equals(role))
childMap.put(entry1.getKey(), entry1.getValue());
}
userMap.put(entry.getKey(), childMap);
}
printMap(userMap);
}
private static void printMap(Map<Integer, Map<Integer, String>> parentMap) {
for(Map.Entry<Integer, Map<Integer,String> > entry: parentMap.entrySet()){
System.out.println("key: "+entry.getKey());
System.out.println("value: "+entry.getValue());
}
}
private static void initializeData() {
Map<Integer, String > childMap1 = new HashMap<>();
Map<Integer, String > childMap2 = new HashMap<>();
userRole.put("user1", "1");
userRole.put("user2", "2");
userRole.put("user3", "3");
userRole.put("user4", "4");
childMap1.put(1, "one");
childMap1.put(2, "two");
childMap1.put(3, "three");
childMap1.put(4, "four");
parentMap.put(1, childMap1);
childMap2.put(1, "one");
childMap2.put(2, "two");
childMap2.put(3, "three");
parentMap.put(2, childMap2);
}
}
Output is:
key: 1
value: {1=one}
key: 2
value: {1=one}
You could use Collectors.toMap there as:
Map<Integer, Map<Integer, String>> userMap = parentMap.entrySet().stream()
.collect(Collectors.toMap(Map.Entry::getKey, entry -> entry.getValue()
.entrySet().stream()
.filter(en -> en.getKey().equals(role))
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue))));
But note, there is no significant performance efficiency that you gain here. Just readability and you could have possibly written that as :
Map<Integer, Map<Integer, String>> usersMap = new HashMap<>(parentMap);
usersMap.values().forEach(innerMap -> innerMap.entrySet().removeIf(en -> !en.getKey().equals(role)));
E.g
Map<Home, List<People>> ihm = new TreeMap<Home, List<People>>();
and data goes like:
ihm.put(new Home(...), Arrays.asList(new People(...),
new People(...),
new People(...));
ihm.put(new Home(...), Arrays.asList(new People(...),
new People(...));
I want to sort it by the no. of people living in the house.
How can i achieve this using comparator or comparable?
It should not be done as property of the map's key Home, as you might want to add/remove people to a Home, corrupting the map.
Instead sort it dynamically:
ihm.entrySet().stream()
.sort(Comparator.comparingInt(es -> -es.getValue().size())) // Decreasing; neg. sizes.
.forEach(es -> System.out.printf("...%n", ...));
An Example of how this could be done.
public static void main(String[] args){
Map<Home, List<People>> ihm = new HashMap<Home, List<People>>();
ihm.put(new Home(3), Arrays.asList(new People(1), new People(2),new People(3)));
ihm.put(new Home(2), Arrays.asList(new People(1), new People(4)));
ihm.put(new Home(4), Arrays.asList(new People(5), new People(4),new People(2),new People(3)));
ihm.put(new Home(1), Collections.singletonList(new People(5)));
System.out.println("\nUnSorted Map :");
for (Map.Entry<Home, List<People>> entry:ihm.entrySet()) {
System.out.println(entry.getKey());
}
Map<Home,List<People>> result = sortByValueCount(ihm);
System.out.println("\nSorted Map :");
for (Map.Entry<Home, List<People>> entry:result.entrySet()) {
System.out.println(entry.getKey());
}
}
public static Map<Home, List<People>> sortByValueCount(final Map<Home,List<People>> homeListMap) {
return homeListMap.entrySet()
.stream()
.sorted((e1, e2) -> Integer.compare(e2.getValue().size(), e1.getValue().size()))
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (e1, e2) -> e1, LinkedHashMap::new));
}
static class Home{
int size;
public Home(int size) {
this.size = size;
}
#Override
public String toString() {
return "Home{" +
"size=" + size +
'}';
}
}
static class People{
int peopleNumber;
public People(int peopleNumber) {
this.peopleNumber = peopleNumber;
}
}
I have set the Home size to be equivalent to the size of elements within it for better understanding.
Can you try below code ?
public class HomeMain {
public static List<Map.Entry<String, Integer>> sortByValue(Map<String, Integer> wordMap){
Set<Map.Entry<String, Integer>> set = wordMap.entrySet();
List<Map.Entry<String, Integer>> list = new ArrayList<Map.Entry<String, Integer>>(set);
Collections.sort( list, new Comparator<Map.Entry<String, Integer>>()
{
public int compare( Map.Entry<String, Integer> o1, Map.Entry<String, Integer> o2 )
{
return (o2.getValue()).compareTo( o1.getValue() );
}
} );
return list;
}
public static void main(String[] args) {
Map<Home, List<People>> ihm = new HashMap<Home, List<People>>();
ihm.put(new Home("Home"), Arrays.asList(new People(4),
new People(5),
new People(6)));
ihm.put(new Home("Home1"), Arrays.asList(new People(2),
new People(1),
new People(9)));
ihm.put(new Home("Home2"), Arrays.asList(new People(3),
new People(6),
new People(2)));
ihm.put(new Home("Home3"), Arrays.asList(new People(1),
new People(7),
new People(6)));
Map<String, Integer> newMap = new HashMap<String, Integer>();
Iterator<Map.Entry<Home, List<People>>> itr = ihm.entrySet().iterator();
while (itr.hasNext()) {
Map.Entry<Home, List<People>> entry = itr.next();
List<People> p = entry.getValue();
int totalPeople = 0;
for (People people : p) {
totalPeople += people.getNumberOfPeople();
}
newMap.put(entry.getKey().getName(), totalPeople);
}
Iterator<Map.Entry<String, Integer>> it1 = newMap.entrySet().iterator();
System.out.println("UnSorted map:");
while (it1.hasNext()) {
Map.Entry<String, Integer> entry = it1.next();
System.out.println("Key = " + entry.getKey() +
", Value = " + entry.getValue());
}
List<Map.Entry<String, Integer>> sortedList = sortByValue(newMap);
System.out.println("Sorted map:");
for (Map.Entry<String, Integer> entry : sortedList) {
System.out.println(entry.getKey() + " ====" + entry.getValue());
}
}}
public class Home {
String name;
public Home(String homename){
this.name=homename;
}}
public class People {
public int getNumberOfPeople() {
return numberOfPeople;
}
int numberOfPeople;
public People(int numOfPeople){
this.numberOfPeople=numOfPeople;
}}
static <K,V extends Collection> Map<K,V> sortMap(Map<K,V> map){
return map.entrySet().stream()
.sorted((e1, e2) -> Integer.compare(e2.getValue().size(), e1.getValue().size()))
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (e1, e2) -> e1, LinkedHashMap::new));
}
I have a ArrayList of Map<String, object> and I want to sort the list after the color so that the red maps are on the top in the ArrayList, immediately afterward the blue maps and at the end the other colors. Currently I am getting the ArrayList sorted alphabetically. How can I get the maps in the ArrayList sorted as I want?
Code:
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class Test {
public static void main(String[] args) {
List<Map<String, Object>> result = new ArrayList<Map<String, Object>>();
HashMap<String, Object> map1 = new HashMap<String, Object>();
map1.put("name", "John");
map1.put("color", "black");
map1.put("size", 24);
result.add(map1);
System.out.println(map1);
HashMap<String, Object> map2 = new HashMap<String, Object>();
map2.put("name", "Liam");
map2.put("color", "yellow");
map2.put("size", 44);
result.add(map2);
System.out.println(map2);
HashMap<String, Object> map3 = new HashMap<String, Object>();
map3.put("name", "Noah");
map3.put("color", "Pink");
map3.put("size", 43);
result.add(map3);
System.out.println(map3);
HashMap<String, Object> map4 = new HashMap<String, Object>();
map4.put("name", "Ake");
map4.put("color", "red");
map4.put("size", 22);
result.add(map4);
System.out.println(map4);
HashMap<String, Object> map5 = new HashMap<String, Object>();
map5.put("name", "Alex");
map5.put("color", "blue");
map5.put("size", 34);
result.add(map5);
System.out.println(map5);
HashMap<String, Object> map6 = new HashMap<String, Object>();
map6.put("name", "John");
map6.put("color", "red");
map6.put("size", 24);
result.add(map6);
System.out.println(map6);
HashMap<String, Object> map7 = new HashMap<String, Object>();
map7.put("name", "Adward");
map7.put("color", "blue");
map7.put("size", 33);
result.add(map7);
System.out.println(map7);
HashMap<String, Object> map8 = new HashMap<String, Object>();
map8.put("name", "William");
map8.put("color", "red");
map8.put("size", 22);
result.add(map8);
System.out.println(map8);
HashMap<String, Object> map9 = new HashMap<String, Object>();
map9.put("name", "Michael");
map9.put("color", "blue");
map9.put("size", 34);
result.add(map9);
System.out.println(map9);
HashMap<String, Object> map10 = new HashMap<String, Object>();
map10.put("name", "Sophia");
map10.put("color", "green");
map10.put("size", 43);
result.add(map10);
System.out.println(map10);
Collections.sort(result, new Comparator<Map<String, Object>>() {
#Override
public int compare(Map<String, Object> o1, Map<String, Object> o2) {
String color1 = (String) o1.get("color");
String color2 = (String) o2.get("color");
return color1.compareTo(color2);
}
});
}
}
Your Comparator extracts the colors from the maps and simply compares them, which, as you've seen, does so lexicographically. One way to approach such a problem could be assign a numeric value to each color:
Collections.sort(result, new Comparator<Map<String, Object>>() {
#Override
public int compare(Map<String, Object> o1, Map<String, Object> o2) {
return Integer.compare(getMapScore(o1), getMapScore(o2));
}
private int getMapScore(Map<String, Object> map) {
final String color = ((String) map.get("color")).toLowerCase();
switch (color) {
case "red":
return 0;
case "blue":
return 1;
}
return 2;
}
});
You could use enum to define the order
private static enum Order{
red(10),
blue(9),
green(8),
Pink(7),
yellow(6),
black(5);
int val;
Order(int p) {
val = p;
}
int getVal() {
return val;
}
}
Then modify to Comparator as follows:
Collections.sort(result, new Comparator<Map<String, Object>>() {
#Override
public int compare(Map<String, Object> o1, Map<String, Object> o2) {
String color1 = (String) o1.get("color");
String color2 = (String) o2.get("color");
return Order.valueOf(color1).getVal()-Order.valueOf(color2).getVal();
}
});
I think the best way would be use Enum for colors so that it can be sorted in any predefined order and you don't have to worry about adding more condition in the compare method. check the below code for more info.
You can put the colors in enums in the order you want and that will be sorted according to that. No more if else condition required.
import java.util.*;
public class Test {
public enum Colors {
RED, BLUE, BLACK, YELLOW, PINK, GREEN
}
public static void main(String[] args) {
List<Map<String, Object>> result = new ArrayList<Map<String, Object>>();
HashMap<String, Object> map1 = new HashMap<String, Object>();
map1.put("name", "John");
map1.put("color", Colors.BLACK);
map1.put("size", 24);
result.add(map1);
HashMap<String, Object> map2 = new HashMap<String, Object>();
map2.put("name", "Liam");
map2.put("color", Colors.YELLOW);
map2.put("size", 44);
result.add(map2);
HashMap<String, Object> map3 = new HashMap<String, Object>();
map3.put("name", "Noah");
map3.put("color", Colors.PINK);
map3.put("size", 43);
result.add(map3);
HashMap<String, Object> map4 = new HashMap<String, Object>();
map4.put("name", "Ake");
map4.put("color", Colors.RED);
map4.put("size", 22);
result.add(map4);
HashMap<String, Object> map5 = new HashMap<String, Object>();
map5.put("name", "Alex");
map5.put("color", Colors.BLUE);
map5.put("size", 34);
result.add(map5);
HashMap<String, Object> map6 = new HashMap<String, Object>();
map6.put("name", "John");
map6.put("color", Colors.RED);
map6.put("size", 24);
result.add(map6);
HashMap<String, Object> map7 = new HashMap<String, Object>();
map7.put("name", "Adward");
map7.put("color", Colors.BLUE);
map7.put("size", 33);
result.add(map7);
HashMap<String, Object> map8 = new HashMap<String, Object>();
map8.put("name", "William");
map8.put("color", Colors.RED);
map8.put("size", 22);
result.add(map8);
HashMap<String, Object> map9 = new HashMap<String, Object>();
map9.put("name", "Michael");
map9.put("color", Colors.RED);
map9.put("size", 34);
result.add(map9);
HashMap<String, Object> map10 = new HashMap<String, Object>();
map10.put("name", "Sophia");
map10.put("color", Colors.GREEN);
map10.put("size", 43);
result.add(map10);
Collections.sort(result, new Comparator<Map<String, Object>>() {
#Override
public int compare(Map<String, Object> o1, Map<String, Object> o2) {
Colors color1 = (Colors) o1.get("color");
Colors color2 = (Colors) o2.get("color");
return color1.compareTo(color2);
}
});
System.out.println(result);
}
}
ArrayList<HashMap<String, Object>> list = ArrayList<HashMap<String, Object>>()
I have an array list which contains an hashmap, i am able to get the position of my List , now how would i get the key and value of the object in my List.
#Override
public View getDropDownView() {
System.out.println(data.get(position)); // i am getting my List Objects
}
// The below is the output of data.get(position)
{"title":"hello"}, => 0
{"title":"hello1"}, => 1
{"title":"hello2"}, => 2
{"title":"hello3"}, => 3
Try this out :
List<HashMap<String, Object>> list = new ArrayList<HashMap<String, Object>>();
for (Map element : list) {
Set<Map.Entry<String, Object>> entrySet = element.entrySet();
for (Map.Entry<String, Object> mapEntry : entrySet) {
System.out.println("Key is : " + mapEntry.getKey());
System.out.println("Value is : " + mapEntry.getValue());
}
}
Little modification in above code.Please find the below code snippets.
public class Test01 {
public static void main(String[] args) {
ArrayList<HashMap<String, Object>> data = new ArrayList<HashMap<String, Object>>();
HashMap<String, Object> map=new HashMap<String, Object>();
map.put("test_key", "test_value");
data.add(map);
HashMap hashMap = data.get(0);
Iterator<Object> iterator=hashMap.entrySet().iterator();
while(iterator.hasNext()){
Map.Entry<String, Object> entry=(Entry<String, Object>) iterator.next();
System.out.println("Key :"+entry.getKey()+" Value : "+entry.getValue());
}
}
}
i hope this may be help...
With full example try this:
ArrayList<HashMap<String, Object>> list = new ArrayList<HashMap<String,Object>>();
HashMap<String, Object> map1 = new HashMap<String, Object>();
HashMap<String, Object> map2 = new HashMap<String, Object>();
map1.put("title", "hello");
map2.put("title2", "hello2");
list.add(map2);
list.add(map1);
HashMap<String, Object> innerMap;
for(int i=0;i<list.size();i++)
{
innerMap = list.get(i);
for (Map.Entry<String, Object> entry : innerMap.entrySet())
{
System.out.println(entry.getKey() + "/" + entry.getValue());
}
}
Your question leaves much to be desired, but I believe this is what you're looking for
public class HashMapClass {
public static void main(String[] args){
ArrayList<HashMap<String, Object>> data = new ArrayList<HashMap<String, Object>>();
//Get the Hasmap at position
HashMap map = data.get(position);
//Get the data in a the hashmap
Object obj = map.get(key);
}
}
You could use Map.Entry
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
public class Y {
public static void main(String[] args) {
// Your data structure...
List<Map<String, Object>> list = new ArrayList<Map<String, Object>>();
//Add some dummy data
Map<String, Object> map = new HashMap<String, Object>();
map.put("1", "A");
map.put("2", "B");
map.put("3", "C");
//Add the Map to the List
list.add(map);
int positionInList = 0; //Manipulate this how you want
//Use Map.Entry to access both key and value
for (Entry<String, Object> entry : list.get(positionInList).entrySet()) {
String key = entry.getKey();
Object value = entry.getValue();
}
}
}