I want to flatten a nested hashmap. For eg,
Map<String, Object> map = new HashMap();
Map<String, Object> map2 = new HashMap();
Map<String, Object> map3 = new HashMap();
map3.put("key3", 123);
map2.put("key2", map3);
map2.put("key4", "test");
map.put("key1", map2);
map.put("key6", "test2");
This will have structure something similar to this:
{
"key1" : {
"key2" : {"key3" : 123 },
"key4" : "test"
},
"key6" : "test2"
}
This should be flattened to a hashmap with structure similar to this:
{
"key1.key2.key3" : 123,
"key1.key4" : "test",
"key6" : "test2"
}
I tried solving this recursively in Java, but not able to produce the right form. Any help is appreciated.
Can be acheived using Stream#flatMap and recursion.
flatMapper() will be recursively called and it will return a Stream of string builder with child keys appended.
public class NestedHashMap {
private static Stream<StringBuilder> flatMapper(Map.Entry<String, Object> entrySet) {
Object value = entrySet.getValue();
if (value instanceof Map) {
return ((Map<String, Object>) value).entrySet()
.stream()
.flatMap(NestedHashMap::flatMapper)
.map(s -> s.insert(0, entrySet.getKey() + "."));
}
return Stream.of(new StringBuilder(entrySet.toString()));
}
public static void main(String[] args) {
// ... Code in the question
System.out.println(map.entrySet()
.stream()
.flatMap(NestedHashMap::flatMapper)
.collect(Collectors.joining(",\n\t", "{\n\t", "\t\n}")));
}
}
Output:
{
key1.key2.key3=123,
key1.key4=test,
key6=test2
}
Related
I'm trying to iterate the List<Map<String, Object>> and want to check if the code is "approved" or not - if code is having value "approved" then I would like to add "id" as Key and "date" as Value in another hashMap.
List<Map<String, Object>> prodIds = ((List<Map<String, Object>>) myIds.get("result"));
This prodIds returns below set of records:
[{id=[14766724], Date=[1999-01-01]}, {id=[49295837], code=[approved], Date=[2003-04-01]}]
[{id=[58761474621], code=[approved], Date=[2017-09-30]}, {id=[3368781], code=[Cancelled], Date=[2014-01-01]}, {id=[48843224], code=[Cancelled], Date=[2009-01-01]}]
I want the output something like this: If code is "approved" - my new hash map should have value like below:
map.put("49295837", "2003-04-01")
map.put("58761474621", "2017-09-30")
Java Code
List<Map<String, Object>> prodIds = ((List<Map<String, Object>>) myIds.get("result"));
System.out.println("prodIds : " +prodIds );
// [{id=[14766724], Date=[1999-01-01]}, {id=[49295837], code=[approved], Date=[2003-04-01]}]
// [{id=[58761474621], code=[approved], Date=[2017-09-30]}, {id=[3368781], code=[Cancelled], Date=[2014-01-01]}, {id=[48843224], code=[Cancelled], Date=[2009-01-01]}]
Map<String, String> newMap = new HashMap<>();
for (Map<String, Object> map : prodIds) {
for (Map.Entry<String, Object> entry : map.entrySet()) {
String key = entry.getKey();
System.out.println("Key : " +key);
String value = (String) entry.getValue();
System.out.println(" Value : " +value);
}
}
I'm having difficulty how to put the key(id) and value(Date) dynamically if the code value is "approved" into new hash map. It would be really helpful if someone can help me with this.
Appreciated your help in advance!
Thanks
As best as I can determine by your example, this should work. But for each Map<String,Object> I need to know what Object is (e.g. String, List<>, etc).
I am assuming they are lists. If I'm wrong you will get a ClassCastException
public static Map<String, String>
getApproved(List<Map<String, Object>> prodIds) {
Map<String, String> newMap = new HashMap<>();
for (Map<String, Object> map : prodIds) {
if (map.containsKey("code") &&
((List<String>) map.get("code")).get(0)
.equals("approved")) {
newMap.put(((List<String>) map.get("id")).get(0),
(String) ((List<String>) map.get("Date"))
.get(0));
}
}
return newMap;
}
Map<String, String> newMap = getApproved(prodIds);
newMap.entrySet().forEach(System.out::println);
Prints
58761474621=2017-09-30
49295837=2003-04-01
It would help if you could describe all your data structures. Like what is the Object type of map?
I am having JSON like this.
{
"mappingData": {
"input.data.DT": "Integer",
"input.data.DTF": "STRING"
}
}
And nested function like this.
Functions.test2(Functions.test1(Functions.test3(input.data.DTF),input.data.DT,"string","int"),input.data.DTF)
Now I want to replace the keys in mappingdata json or map key with value in the respective position of function. How I can do this as if I use contains and replace and it won't replace as mappingData key input.data.DTF which is similar to input.data.DT So, replace will be inconsistant.
How can I do this.
EXPECTED RESULT:
Functions.test2(Functions.test1(Functions.test3(STRING),Functions.test2(Functions.test1(Functions.test3(STRING),Integer,"string","int"),STRING),"string","int"),STRING)
JAVA code:
Map<String, String> mapData = (Map<String, String>) data.get("mappingData");
System.err.println("mapData===>" + mapData);
for (Map.Entry<String, String> entry : map.entrySet()) {
try {
String function = entry.getValue();
//System.out.println("function===="+function);
if (function.contains("Functions")) {
for (Entry<String, String> entry1 : mapData.entrySet()) {
if (function.contains(entry1.getKey())) {
function = function.replace(entry1.getKey(), entry1.getValue());
}
}
}
}
}
I need to fill map with Iterable<Map.Entry>. The following is an original java code:
Iterable<Map.Entry<String, String>> conf;
Iterator<Map.Entry<String, String>> itr = conf.iterator();
Map<String, String> map = new HashMap<String, String>();
while (itr.hasNext()) {
Entry<String, String> kv = itr.next();
map.put(kv.getKey(), kv.getValue());
}
I have to rewrite it in groovy. Is there a concise groovy-way to do it?
I'd use collectEntries for that. It's similar to collect, but it's purpose is to create a Map.
def sourceMap = ["key1": "value1", "key2": "value2"]
Iterable<Map.Entry<String, String>> conf = sourceMap.entrySet()
def map = conf.collectEntries {
[(it.key): it.value]
}
Note the round braces around it.key that allow you to use a variable reference as key of the newly generated Entry.
In Groovy you can use the each closure instead of Iterator as follows
Map<Map.Entry<String, String>> sourceMap = ["key1" : "value1", "key2" : "value2"]
Map<Map.Entry<String, String>> targetMap = [:]
sourceMap.each{ key, value ->
targetMap[key] = value
}
println targetMap
Working example here : https://groovyconsole.appspot.com/script/5100319096700928
I have a json string which I need to validate and find any other keys other than in a list is there in the json string. The sample json string is
{
"required" : true,
"requiredMsg" : "Title needed",
"choices" : [ "a", "b", "c", "d" ],
"choiceSettings" : {
"a" : {
"exc" : true
},
"b" : { },
"c" : { },
"d" : {
"textbox" : {
"required" : true
}
}
},
"Settings" : {
"type" : "none"
}
}
To allow only predifined keys is exsist in the json string I want to get all the keys in the json string. How can I obtain all the keys in the json string. I am using jsonNode. My code till now is
JsonNode rootNode = mapper.readTree(option);
JsonNode reqiredMessage = rootNode.path("reqiredMessage");
System.out.println("msg : "+ reqiredMessage.asText());
JsonNode drNode = rootNode.path("choices");
Iterator<JsonNode> itr = drNode.iterator();
System.out.println("\nchoices:");
while (itr.hasNext()) {
JsonNode temp = itr.next();
System.out.println(temp.asText());
}
How to get all the keys from the json string using JsonNode
forEach will iterate over children of a JsonNode (converted to String when printed) and fieldNames() gets an Iterator<String> over keys. Here are some examples for printing elements of the example JSON:
JsonNode rootNode = mapper.readTree(option);
System.out.println("\nchoices:");
rootNode.path("choices").forEach(System.out::println);
System.out.println("\nAllKeys:");
rootNode.fieldNames().forEachRemaining(System.out::println);
System.out.println("\nChoiceSettings:");
rootNode.path("choiceSettings").fieldNames().forEachRemaining(System.out::println);
You'll probably need fields() at some point that returns an Iterator<Entry<String, JsonNode>> so you can iterate over key, value pairs.
This should do it.
Map<String, Object> treeMap = mapper.readValue(json, Map.class);
List<String> keys = Lists.newArrayList();
List<String> result = findKeys(treeMap, keys);
System.out.println(result);
private List<String> findKeys(Map<String, Object> treeMap , List<String> keys) {
treeMap.forEach((key, value) -> {
if (value instanceof LinkedHashMap) {
Map<String, Object> map = (LinkedHashMap) value;
findKeys(map, keys);
}
keys.add(key);
});
return keys;
}
This will print out result as
[required, requiredMsg, choices, exc, a, b, c, required, textbox, d, choiceSettings, type, Settings]
The accepted answer works out great but issues a warning, "Type safety: The expression of type Map needs unchecked conversion to conform to Map <String, Object>"
This answer led me to change that line to the following to eliminate the warning:
Map<String, Object> treeMap = mapper.readValue(json, new TypeReference<Map<String, Object>>() {});
List in the json was not supported in the accepted solution. Here is what I propose:
public List<String> getAllNodeKeys(String json) throws JsonProcessingException {
Map<String, Object> treeMap = objectMapper.readValue(json, new TypeReference<>() {
});
return findKeys(treeMap, new ArrayList<>());
}
private List<String> findKeys(Map<String, Object> treeMap, List<String> keys) {
treeMap.forEach((key, value) -> {
if (value instanceof LinkedHashMap) {
LinkedHashMap map = (LinkedHashMap) value;
findKeys(map, keys);
} else if (value instanceof List) {
ArrayList list = (ArrayList) value;
list.forEach(map -> findKeys((LinkedHashMap) map, keys));
}
keys.add(key);
});
return keys;
}
I have an ArrayList of HashMap. I want to search a HashMap in it but unable to find a way to achieve this. Please suggest me how it can be done?
Thanks.
Answer to your question the way i understood it!
for (HashMap<String, String> hashMap : yourArrayList)
{
// For each hashmap, iterate over it
for (Map.Entry<String, String> entry : hashMap.entrySet())
{
// Do something with your entrySet, for example get the key.
String sListName = entry.getKey();
}
}
Your Hashmap might use other types, this one uses Strings.
See if this helps:
#Test
public void searchMap() {
List<Map<String, String>> listOfMaps = new ArrayList<Map<String,String>>();
Map<String, String> map1 = new HashMap<String, String>();
map1.put("key1", "value1");
Map<String, String> map2 = new HashMap<String, String>();
map1.put("key2", "value2");
Map<String, String> map3 = new HashMap<String, String>();
map1.put("key3", "value3");
listOfMaps.add(map1);
listOfMaps.add(map2);
listOfMaps.add(map3);
String keyToSearch = "key2";
for (Map<String, String> map : listOfMaps) {
for (String key : map.keySet()) {
if (keyToSearch.equals(key)) {
System.out.println("Found : " + key + " / value : " + map.get(key));
}
}
}
}
Cheers!
Object myObj;
Object myKey;
//Traverse the list
for(HashMap curMap : listOfMaps){
//If this map has the object, that is the key doesn't return a null object
if( (myObj = curMap.get(myKey)) != null) {
//Stop traversing because we are done
break;
}
}
//Act on the object
if(myObj != null) {
//TODO: Do your logic here
}
If you are looking to get the reference to the Map instead of the object (for whatever reason) same process applies, except you just store the reference to the map:
Map myMap;
Object myKey;
//Traverse the list
for(HashMap curMap : listOfMaps){
//If this map has the object, that is the key doesn't return a null object
if(curMap.get(myKey) != null) {
//Store instance to the map
myMap = curMap;
//Stop traversing because we are done
break;
}
}
//Act on the map
if(myMap != null) {
//TODO: Do your logic here
}
Try below improved code for searching the key in a list of HashMap.
public static boolean searchInMap(String keyToSearch)
{
boolean returnVal = false;
List<Map<String, String>> listOfMaps = new ArrayList<Map<String, String>>();
Map<String, String> map1 = new HashMap<String, String>();
map1.put("key1", "value1");
Map<String, String> map2 = new HashMap<String, String>();
map1.put("key2", "value2");
Map<String, String> map3 = new HashMap<String, String>();
map1.put("key3", "value3");
listOfMaps.add(map1);
listOfMaps.add(map2);
listOfMaps.add(map3);
for (Map<String, String> map : listOfMaps)
{
if(map.containsKey(keyToSearch))
{
returnVal =true;
break;
}
}
return returnVal;
}
The Efficient way i've used to search a hashmap in an arraylist without using loops. Since loop makes execution time longer
try{
int index = list.indexOf(map); // map is your map to find in ArrayList
if(index>=0){
HashMap<String, String> map = array_list.get(index);
// Here you can get your values
}
}
catch(Exception e){
e.printStackTrace();
Log.i("HashMap","Not Found");
}
if you have an ArrayList like this one: ArrayList<HashMap<String, String>>
and you want to compare one of the values inside the HashMap try this code.
I use it to compare settings of my alarm notifications.
for (HashMap<String, String> map : AlarmList) {
for (String key : map.keySet())
{
if (key.equals("SendungsID"))
{
if(map.get(key).equals(alarmMap.get("AlarmID")))
{
//found this value in ArrayList
}
}
}
}