In my code i have a
Map<String,Map<String,customObject>>
I am not sure how to iterate over this map and get the values from it.
What i am trying to do here is get the enclosing Map by passing in the key to the external Map.
When i get the enclosing map i need to iterate over it and get key and value from it.
Can you please let me know how i can do this as i am kind of stuck here.
Any example or code of a similar type can be of a great help to understand it better.
Thanks
Vikeng21
You can use the entry set of both Maps. something like this:
Map<String,Map<String,String>> map1 = ...
Set<Entry<String,Map<String,customObject>>> entrySet1 = map1.entrySet();
for (Entry<String, Map<String, customObject>> entry1 : entrySet1) {
Map<String,String> map2 = entry1.getValue();
Set<Entry<String, customObject>> entrySet2 = map2.entrySet();
for (Entry<String, customObject> entry2 : entrySet2) {
System.out.println(entry1.getKey() +" -> "+entry2.getKey()+" -> "+entry2.getValue());
}
}
To iterate over hashmap entries...
for (Map.Entry<String, Map<String, Object>> ent : hashmap.entrySet())
{
//ent.getKey(); is the key [String]
//ent.getValue(); is the value [Map<String, Object>]
}
Now work out from there, it's basically the same.
I am not sure how to iterate over this map and get the values from it
You would iterate over the map's values like with any maps - see below an example that uses such a structure.
Map<String, CustomObject> innerMap = new HashMap<String, CustomObject> ();
innerMap.put("abc", new CustomObject());
Map<String, Map<String, CustomObject>> externalMap = new HashMap<String, Map<String, CustomObject>> ();
externalMap.put("map1", innerMap);
//iterate over all the maps contained in externalMap
for (Map<String, CustomObject> inner : externalMap.values()) {
System.out.println(inner);
}
If you also need to access the keys, you can iterate over the entry set:
for (Entry<String, Map<String, CustomObject>> e : externalMap.entrySet()) {
System.out.println(e.getKey()); //map1
System.out.println(e.getValue()); //innerMap
}
I think this example will give your answer....
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
public class MapInMap {
public static void main(String[] args) {
Map<String, MyObj> innerMap01 = new HashMap<String, MyObj>();
Map<String, MyObj> innerMap02 = new HashMap<String, MyObj>();
innerMap01.put("OneOne", new MyObj());
innerMap02.put("TwoOne", new MyObj());
Map<String, Map<String, MyObj>> maps = new HashMap<String, Map<String, MyObj>>();
maps.put("One", innerMap01);
maps.put("Two", innerMap02);
for (Entry<String, Map<String, MyObj>> map : maps.entrySet()) {
for (Entry<String, MyObj> innerObject : map.getValue().entrySet()) {
// your logic
}
}
}
}
class MyObj {
int i;
}
Related
Im storing 2 map with different structure in single map like below,
Map<String, List<String>> colMap = new HashMap<String, List<String>>();
Map<String, String> appMap = new HashMap<String, String>();
// colMap assigning some values
// appMap assigning some values
Map<String, Map> mainMap = new HashMap<String, Map>();
mainMap.put("appMap", appMap);
mainMap.put("colMap", colMap);
I want to get map one by one and iterate the map.
If I try get map like below, getting error,
.......
Map colMap = map.get("colMap");
for(Entry<String, List<String>> entry : colMap.entrySet())
Error: Type mismatch: cannot convert from element type Object to Map.Entry<String,List<String>>
Why not just create a simple container POJO class (or record in Java 16+) for the two maps instead of mainMap and keep the relevant type-safety which to do it Java-way?
public class MapPojo {
private final Map<String, List<String>> colMap;
private final Map<String, String> appMap;
public MapPojo(Map<String, List<String>> colMap, Map<String, String> appMap) {
this.colMap = colMap;
this.appMap = appMap;
}
// getters, etc.
}
MapPojo mainMap = new MapPojo(colMap, appMap);
Error you are getting because when you are doing map.get operation your reference is Just Map without any Generics which will treated as Object class's reference. You should use generics like below and it will work -
Map<String, List<String>> colMap = map.get("colMap");
for(Entry<String, List<String>> entry : colMap.entrySet())
I have the following sample result when I query a database :
dataList = [{ name : name1, rollno: rollno1 }, { name : name2, rollno: rollno2 } ]
I want to convert this list of hashmaps into a single hashmap using Java 8 streams.
I tried using Collectors.toMap() but i am not sure how to refer to rollNo as key and the hashmap as the value inside the toMap method.
Exected output :
{ rollno1 : { name : name1, rollno: rollno1 } , rollno2 : { name : name2, rollno: rollno2 } }
I tried doing it using a for each loop on the list and then adding the rollno as key to a hashmap and the hashmap as value itself of that rollno.
HashMap<String,HashMap<String,String>> newMap = new HashMap();
for(HashMap<String,String> record : dataList){
String key = record.get("rollno").toString();
newMap.put(key,record);
}
Is there a way to refactor this code using functional streams in Java 8?
Will using streams collect method give any performance advantage over the foreach for doing this?
Will appreciate any leads. Thanks
Here's complete example how to do it
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.stream.Collectors;
public class Main {
public static void main(String[] args) {
List<HashMap<String, String>> input = new ArrayList<>();
HashMap<String, String> subinput1 = new HashMap<>();
subinput1.put("name", "name1");
subinput1.put("rollno", "rollno1");
input.add(subinput1);
HashMap<String, String> subinput2 = new HashMap<>();
subinput2.put("name", "name2");
subinput2.put("rollno", "rollno2");
input.add(subinput2);
HashMap<String, HashMap<String, String>> result = (HashMap<String, HashMap<String, String>>) input.stream()
.collect(Collectors.toMap(v -> (String) v.get("rollno"), e -> e));
System.out.println(result);
}
}
It iterates over a collection of HashMaps, takes the key in which it should be stored in the result HashMap, then it creates a Map of Maps where the key is the "rollno" from the input map, and value is the input map itself.
As I don't know the type of Object you are using, so I am performing this on String. But it is valid for any type of object.
HashMap result = (HashMap<String, HashMap<String, String>>) listOfHashMaps.stream()
.collect(Collectors.toMap(e-> e.get("roll"),e->e));
As type casting will help you to achieve this.
You can use Collectors.toMap with Function.identity() as below,
list.stream()
.collect(toMap(e->e.get("rollno"), Function.identity()));
public static void main(String[] args) {
List<HashMap<String, String>> input = new ArrayList<>();
HashMap<String, String> subinput1 = new HashMap<>();
subinput1.put("name", "name1");
subinput1.put("rollno", "rollno1");
input.add(subinput1);
HashMap<String, String> subinput2 = new HashMap<>();
subinput2.put("name", "name2");
subinput2.put("rollno", "rollno2");
input.add(subinput2);
//Test key conflict
HashMap<String, String> subinput3 = new HashMap<>();
subinput2.put("name", "name3");
subinput2.put("rollno", "rollno2");
input.add(subinput2);
System.out.println("input:"+ JSONObject.toJSONString(input));
HashMap<String, HashMap<String, String>> result = (HashMap<String, HashMap<String, String>>)
input.stream()
.collect(Collectors.toMap(
v -> (String) v.get("rollno"),
Function.identity(),(oldValue, newValue) -> newValue
));
//fastjson hashmap-toString use =
System.out.println(JSONObject.toJSONString(result));
}
Probably something like this:
Map<RollNo, List<Roll>> rollsPerType = rolls.stream()
.collect(groupingBy(Roll::getRollNo));
where Roll is the main object and RollNo is the property inside (since you didn't provide the actual definitions).
I have a nested maps object like below
{12345={{"status":"200","outcome":"Success","message":"Account created"}}
{23121={{"status":"400","outcome":"Exception","message":"Invalid State value"}}
{43563={{"status":"200","outcome":"Success","message":"Account updated"}}
{72493={{"status":"400","outcome":"Exception","message":"Bad Request"}}
I need to transform this into Map<String, List<Map<String, Map<String, String>>> where the key of outer map is value of the status ( 200 or 400 ) and the value is the list of original maps that have status = 200 or 400 or other valid values from the inner map.
So, the new structure would look like
{{200={[{12345={"status":"200","outcome":"Success","message":"Account created"}},
{43563={"status":"200","outcome":"Success","message":"Account updated"}}
]
},
{400={[{23121={"status":"400","outcome":"Exception","message":"Invalid State value"}},
{72493={"status":"400","outcome":"Exception","message":"Bad Request"}}
]
}
}
Ultimately, I need to generate a report based on the different stati.
This is what I have started with, but am stuck.
I want to loop through outer map, get the inner map, get the value of status key and add the map to a list based on status code value.
This is how I am doing it using loops
private static Map<String, List<Map<String, Map<String, String>>>> covertToReport(Map<String, Map<String, String>> originalMap) {
Map<String, List<Map<String, Map<String, String>>>> statusBasedListOfMaps = new TreeMap<>();
//loop through the map
//for each key, get the inner map
//get the status value for each inner map
List<Map<String, Map<String, String>>> accountsMapsList;
for (Entry<String, Map<String, String>> entry : originalMap.entrySet()) {
String accNum = entry.getKey();
Map<String, String> childMap = entry.getValue();
String stausVal = childMap.get("status");
accountsMapsList = statusBasedListOfMaps.get(stausVal) == null ? new ArrayList<>() : statusBasedListOfMaps.get(stausVal);
accountsMapsList.add((Map<String, Map<String, String>>) entry);
statusBasedListOfMaps.put(stausVal, accountsMapsList);
}
return statusBasedListOfMaps;
}
Of course, the below code doesn't compile, but that is what I am trying to get.
private static void covertToReport(Map<String, Map<String, String>> originalMap) {
Map<String, List<Map<String, Map<String, String>>>> statusBasedListOfMaps;
statusBasedListOfMaps = originalMap.entrySet()
.stream()
.filter(e -> e.getValue()
.values()
.stream()
.map(innerMap -> Collectors.toList())
.collect(Collectors.toMap(Map.Entry::getKey, Collectors.toList(e)));
Is this possible?
You can just use Collectors.groupingBy() with Collectors.mapping():
private static Map<String, List<Map<String, Map<String, String>>>> convertToReport(Map<String, Map<String, String>> originalMap) {
return originalMap.entrySet().stream()
.collect(Collectors.groupingBy(e -> e.getValue().get("status"),
Collectors.mapping(Map::ofEntries, Collectors.toList())));
}
You group by status and then map the associated entry to an own map using Map.ofEntries(). If you are using Java you can use this instead of Map::ofEntries:
e -> new HashMap<>() {{ put(e.getKey(), e.getValue()); }}
The result will be this:
200=[
{12345={status=200, message=Account created, outcome=Success}},
{43563={status=200, message=Account created, outcome=Success}}
],
400=[
{72493={status=400, message=Invalid State value, outcome=Exception}},
{23121={status=400, message=Invalid State value, outcome=Exception}}
]
Your function return a Map<String, List<Map<String, Map<String, String>>>>, but your structure look like Map<String, Map<String, Map<String, String>>>
If what you really like is a Map<String, Map<String, Map<String, String>>> here is the code:
Map<String, Map<String, Map<String, String>>> result= map.entrySet().stream().collect(Collectors.groupingBy(entry -> entry.getValue().get("status"), Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)));
I am getting a syntax error which I am not able to resolve. I am using Java 1.8.
import java.util.*;
public class datatypetest
{
public static void main(String args[])
{
Map map1 = new HashMap();
map1.put("1", "Deepak");
map1.put("2", "Ajay");
System.out.println(map1);
System.out.println(map1.keySet());
for (Map.Entry<String, String> entry : map1.entrySet())
{
System.out.println(entry.getKey() + "/" + entry.getValue());
}
}
}
But I am getting this error:
incompatible types: Object can not be converted to Entry<String,String>
You created a raw map :
Map map1 = new HashMap();
Change it to:
Map<String,String> map1 = new HashMap<String,String>();
If you instantiate the map as a raw Map, you can't use Map.Entry<String, String> in the loop (you can only use the raw Map.Entry).
You need to use Generics to avoid such Type of Conflicts i.e
Map<String, String> map1 = new HashMap<String, String>();
Generics provides Type Safety.
And in addition I've found in your code that your Class name didn't follow best practices. It indeed must start with Capital letter since it's a best practice entire JAVA world follows
Try This
import java.util.*;
public class DataTypeTest {
public static void main(String args[]){
Map<String, String> map1 = new HashMap<String, String>();
map1.put("1", "Deepak");
map1.put("2", "Ajay");
System.out.println(map1);
System.out.println(map1.keySet());
for (Map.Entry<String, String> entry : map1.entrySet())
{
System.out.println(entry.getKey() + "/" + entry.getValue());
}
}
}
Happy Programming :)
because you have created
Map map1 = new HashMap();
can be of any type(not just string) so java is not allowing you to downcast it.
I have the following structure:
import java.util.LinkedHashMap;
...
LinkedHashMap <String, Object>level0 = new LinkedHashMap<String, Object>();
LinkedHashMap <String, Object>level1 = new LinkedHashMap<String, Object>();
LinkedHashMap <String, Object>level2 = new LinkedHashMap<String, Object>();
LinkedHashMap <String, Object>level3 = new LinkedHashMap<String, Object>();
level1.put("level2", level2);
level2.put("level2", level3);
level0.put("level1", level1);
System.out.println(level0);
Output this:
{
level1={
level2={}
}
}
I need to set a value through a "path" (or something), would be something like this:
MapThisObject example = new MapThisObject(level0);
example.putValue("level1.level2", "string", "test");
example.putValue("level1.level2", "int", 1);
example.putValue("level1.level2", "object", new LinkedHashMap());
System.out.println(example.result());
/*output:
{
level1={
level2={
string="test",
int=1,
Object={}
}
}
}
*/
In other words, there is the possibility to put or set values for "multidimensional objects" through a "path" (like Xpath)?
A simple example
public static void set(Map<String, Object> map, String path, Object value) {
String[] parts = path.split("\\.");
for(int i = 0; i < parts.length-1 ; i++) {
String key = parts[i];
Map<String, Object> map2 = (Map<String, Object>) map.get(key);
if (map2 == null) {
map.put(key, map2 = new LinkedHashMap<String, Object>());
}
map = map2;
}
map.put(parts[parts.length - 1], value);
}
set(example, "level1.level2.string", "test");
set(example, "level1.level2.int", 1);
From what you've described, it sounds like all you need is a map containing maps, nested to however many axes you're trying to select from.
The alternative would be to build your own tree structure, of course. Or to express it as an XML DOM tree, which would let you use standard XPath.