In order to get the names of the Sections with True or NotNull/NotEmpty values I am creating a Map from the following Java object then iterating over it.
public class Assessment {
private Boolean section1Checkbox1;
private Boolean section1Checkbox2;
private Boolean section1Comments;
private Boolean section2Checkbox1;
private Boolean section2Checkbox2;
private Boolean section2Comments;
more sections.....
I have converted the object to a Map which I then iterate over:
Map<String, Object> map = oMapper.convertValue(needsAssessment, Map.class);
Iterator it = map.entrySet().iterator();
while (it.hasNext()) {
Map.Entry pair = (Map.Entry)it.next();
if (pair.getValue()==true||NotNull) {
// Get Section Name
String[] sectionName = pair.getKey().toString().split("(?=\\p{Upper})");
System.out.println(sectionName[0]);
}
}
There is a error with the pair.getValue() test:
Is there a way to test for true (if boolean) and NotNull or Empty (if
string) in one statement?
(Or a better approach?)
This code works thanks #Lino :
Map<String, Object> map = oMapper.convertValue(assessment, Map.class);
System.out.println(map);
Iterator it = map.entrySet().iterator();
while (it.hasNext()) {
Map.Entry pair = (Map.Entry)it.next();
if (pair.getValue() instanceof Boolean) {
Boolean currentCheckbox = (Boolean) pair.getValue();
// Get Section/Subject Name
System.out.println(pair.getKey());
if (currentCheckbox) {
String[] sectionName = pair.getKey().toString().split("(?=\\p{Upper})");
System.out.println(sectionName[0]);
}
}
}
Here's some code, which shows the more idiomatic Java 8+ way of using lambdas and streams for collection filtering and transforming:
Map<String, Object> map = oMapper.convertValue(assessment, Map.class);
map.entrySet()
// stream all entries
.stream()
// filter by value being TRUE (this is null safe)
.filter((e) -> Boolean.TRUE.equals(e.getValue()))
// transform entry to key split by regex
.map(e -> e.getKey().split("(?=\\p{Upper})"))
// transform to first array item
.map(a -> a[0])
// print
.forEach(System.out::println);
Related
Using Map of key to iterate and based on condition returning HashMap,need to collect return map below code.
trying to convert below java code in java 8
for (String key : sectionsJson.keySet()) {
Map<String, Object> section = (Map<String, Object>) sectionsJson.get(key);
if (index == (Integer) section.get(SECTION_FIELD_KEY_INDEX)) {
section.put(SECTION_FIELD_KEY_SECTION_KEY, key);
return section;
}
}
any suggestion.
It looks like you want to produce a Map having at most a single entry.
Map<String,Object> map =
sectionsJson.entrySet()
.stream()
.filter(e -> {
Map<String, Object> section = e.getValue ();
return index == (Integer) section.get(SECTION_FIELD_KEY_INDEX);
}
.map(e -> new SimpleEntry<> (SECTION_FIELD_KEY_SECTION_KEY, e.getKey ()))
.limit(1)
.collect(Collectors.toMap(Map.Entry::getKey,Map.Entry::getValue));
It looks like your original code is simpler.
Perhaps you can simply search for the desired key:
String value =
sectionsJson.entrySet()
.stream()
.filter(e -> {
Map<String, Object> section = e.getValue ();
return index == (Integer) section.get(SECTION_FIELD_KEY_INDEX);
}
.map(Map.Entry::getKey)
.findFirst()
.orElse(null);
since you are producing a Map having (at most) a single value and a constant key, so the value is the only data the Stream pipeline should be searching for.
As per your existing code. You are returning the map as soon as it finds any match. Same thing you can do using java 8 as well.
Optional<Integer> findAny = sectionsJson.keySet().stream().filter(key -> {
Map<String, Object> section = (Map<String, Object>)sectionsJson.get(key);
if (index == (Integer)section.get("SECTION_FIELD_KEY_INDEX")) {
section.put("SECTION_FIELD_KEY_SECTION_KEY", key);
return true;
}
return false;
}).findFirst();
if (findAny.isPresent()) {
System.out.println(sectionsJson.get(findAny.get()));
}
Depending on what you want to achieve following might be also possible solutions:
simplifying the loop
for (Map.Entry<String, Map<String, Object>> entry : sectionsJson.entrySet()) {
Map<String, Object> section = entry.getValue();
if (index == section.get(SECTION_FIELD_KEY_INDEX)) {
section.put(SECTION_FIELD_KEY_SECTION_KEY, entry.getKey());
return section;
}
}
// add the code for the case when no section was found
separate stream processing and mutating the element
// find the section
Optional<Map.Entry<String, Map<String, Object>>> first = sectionsJson.entrySet().stream()
.filter(e -> (Integer) e.getValue().get(SECTION_FIELD_KEY_INDEX) == index)
.findFirst();
// mutate the section
if (first.isPresent()) {
Map.Entry<String, Map<String, Object>> sectionJson = first.get();
sectionJson.getValue().put(SECTION_FIELD_KEY_SECTION_KEY, sectionJson.getKey());
return sectionJson.getValue();
}
// add the code for the case when no section was found
I have a HashSet of (a hashmap of (string and list of (hashmap of (two strings))))
HashSet<HashMap<String1,List<HashMap<String2,HashMap<String3,String4>>>>>
Now, I need to search with String inputs (StrA and StrB) and this should search the HashSet on
StrA-->String1
StrB-->String2
and it should return the hashMap of String 3 and String 4.
This is what I tried.
HashSet<HashMap<String,List<HashMap<String,HashMap<String,String>>>>> ObjList;
public void getElement(String strA, String strB) {
if(ObjList.contains(strA) && ObjList.contains(strB))
System.out.println("Yes");
}
A solution using Streams would be :
HashSet<HashMap<String, List<HashMap<String, HashMap<String, String>>>>> fooSet = //;
String string1 = "string1";
String string2 = "string2";
HashMap<String, String> mapFound;
mapFound = fooSet.stream() // iterate over HashSet
.filter(map -> map.containsKey(string1)) // keep maps that contains string1
.findFirst() // take first map that match
.orElseGet(HashMap::new) // take it really (or create new Map)
.getOrDefault(string1, new ArrayList<>()) // take the List associated as value,or new List if not exists
.stream() // iterate over the list
.filter(map -> map.containsKey(string2)) // keep maps that contains string2
.findFirst() // take first map that match
.orElseGet(HashMap::new) // take it really (or create new Map)
.getOrDefault(string2, new HashMap<>()); // take HashMap associated as value, or new Map if not found
Solution with classic for each loop would be :
HashMap<String, String> mapFound;
for (HashMap<String, List<HashMap<String, HashMap<String, String>>>> map : fooSet) {
if (map.containsKey(string1)) {
List<HashMap<String, HashMap<String, String>>> list = map.get(string1);
for(HashMap<String, HashMap<String, String>> map2 : list){
if(map2.containsKey(string2)){
mapFound = map2.get(string2);
}
}
}
}
There is no other choice than iterating both, the outer Set and the inner List (untested):
HashSet<HashMap<String1,List<HashMap<String2,HashMap<String3,String4>>>>> outer = //...
HashMap<String3,String4> result =
outer.stream()
.findFirst(map1-> map1.containsKey(string1))
.get()
.stream()
.findFirst(map2-> map2.containsKey(string2))
.get();
How do I access a list inside a map of type Map <String, Object>?
public Map<String, Object> getListInsideMapObject(Long id, Date from) {
Map<String, Object> result = new HashMap<>();
List<Map<String, Object>> mapList = new ArrayList<>();
List<MappedList> conTime = new ArrayList<>();
conTime = xxxRepository.findByxxx(id, from);
Map<String, Object> map = xxxService.xxx(id);
List<String> times = (List<String>) map.get("xxx");
for (MappedList t : conTime) {
int num = 0;
Map<String, Object> res = new HashMap<>();
res.put("x", "");
res.put("status", null);
for (Contraction c : con) {
num++;
res.put("status", "stat");
res.put("x", new Date());
}
}
res.put("y", num);
mapList.add(res);
result.put("mapList", mapList);
result.put("mapListA", mapListA);
result.put("mapListB", mapListB);
//etc
return result;
}
I am trying to call this service (getListInsideMapObject) and access each list from this map and loop through each list. for example in class xxx i want to call getListInsideMapObject(Long id, Date from) as a service and access each list from the map
I imagine you want something like this:
public NewClass1() {
// have an instance from the class that gives you the map
ClassThatBuildsTheMap mapClass = new ClassThatBuildsTheMap();
// get the map. must provide id and date
Map <String, Object> myMap = mapClass.getListInsideMapObject(id, date);
// access the lists inside the map
useListInsideAMap(myMap);
}
private void useListInsideAMap(Map<String, Object> map){
// Prior to Java8:
for (Map.Entry<String, Object> entry : map.entrySet()) {
String key = entry.getKey(); // if you want to use the key
Object value = entry.getValue();
if(value instanceof List){
// I supose it is a list of sytrings
List l = (List) value;
for (Object item : l) {
// Do something with the item from the list
}
}
}
// Java8:
// loop through the map
map.forEach((String key, Object value)->{
// if you want to use key, just call key
// checks if the value (Object) from the map is a list
if(value instanceof List){
List l = (List)value;
// loop through the list
l.forEach((Object item)->{
// Do something with the item from the list
});
}
});
}
You can cast your Object to List
Map<String, Object> result = new HashMap<>();
List<Map<String, Object>> mapList= new ArrayList<>();
result.put("1", mapList);
-------------------------------------------------------
List<Map<String, Object>> = (List<Map<String, Object>>)result.get("1")
Then, you can loop normally using for/foreach.
Also you can use Optional object to get your map value by key and check it before cast to needed type (to avoid ClassCastException issues) :
Map<String, Object> someMap = new HashMap<>();
List<Map<String, Object>> result = Optional.ofNullable(someMap.get("id"))
.filter(obj -> obj instanceof List)
.map(obj -> (List<Map<String, Object>>)obj)
.orElse(Collections.emptyList());
In that case you will have empty List (if element missed or type is not a List) or expected List value.
I want to connect a HashMap's key and value to a string with ':', and transform them to a list.
Example:
Map<String,String> tags = new HashMap<>();
tags.put("k1","v1");
tags.put("k2","v2");
then I want to get the string
k1:v1,k2:v2
my code is:
private String transe(Map<String, String> tags) {
if (tags == null || tags.isEmpty()) {
return DEFAULT_STATUS_GROUP;
}
List<String> tagKVList = new ArrayList<>();
tags.forEach((key, value) -> tagKVList.add(String.join(":", key, value)));
tagKVList.sort((tag1, tag2) -> tag1.compareTo(tag2));
return tagKVList.stream().collect(Collectors.joining(","));
}
How can I remove the local variable tagKVList and make the code clearer?
You don't need the intermediate List. You can Stream the entrySet, map each entry to a String and collect to a single String as you already do :
return tags.entrySet().stream()
.map(e-> String.join(":", e.getKey(), e.getValue()))
.sorted()
.collect(Collectors.joining(","));
I broke my brain on it for a few hours, but need to carry on and found an ugly workaround, but I'd be happy to cleanup my code, here's the problem:
public static void function1(Map<String, Float> map)
{
for(String key : map.keySet()) {
Float val = map.get(key);
// val is null here, throws NPE as soon as we try to use it
}
}
public static void function2(Map<String, Float> map)
{
Iterator<Entry<String, Float>> it = map.entrySet().iterator();
while(it.hasNext()) {
Entry<String, Float> entry = it.next();
String key = entry.getKey();
Float val = entry.getValue();
// do something with key & val, works fine
}
}
the argument Map<String, Float> map of course is correctly initialized and doesn't contain any null value.
on a side note, function1 works fine if I change the argument to Map map and use string pairs only. My goal is to to have only 1 function with generics Map<? extends Object, ? extends Object> map which I could use for both type of maps.
any suggestion appreciated, thanks!
thomas
EDIT: I added some really basic introspection to make the function work with generics. I can confirm that I'm still getting null values when using the keyset, while I followed the suggestion below to use the entryset. here's my code below (the 1st function works fine, while the second returns null elements.
// yeah, it's aweful, but it works.
public static JsonNode map2JSON(Map<? extends Object, ? extends Object> map)
{
ObjectNode dummyObject = Json.newObject();
ArrayNode result = dummyObject.putArray("dummyKey");
for(Entry<?, ?> entry : map.entrySet()) {
ObjectNode mapElementNode = result.addObject();
if("java.lang.String".equalsIgnoreCase(entry.getKey().getClass().getName())) {
String key = (String)entry.getKey();
if("java.lang.Float".equalsIgnoreCase(entry.getValue().getClass().getName())) {
Float val = (Float)entry.getValue();
mapElementNode.put(key, val);
} else if("java.lang.String".equalsIgnoreCase(entry.getValue().getClass().getName())) {
String val = (String)entry.getValue();
mapElementNode.put(key, val);
}
}
}
return result;
}
// result here contains valid keys (the string part) and null values (the float part)
#Deprecated
public static JsonNode mapSF2JSON(Map<String, Float> map)
{
ObjectNode dummyObject = Json.newObject();
ArrayNode result = dummyObject.putArray("dummyKey");
for(String key : map.keySet()) {
ObjectNode mapElementNode = result.addObject();
mapElementNode.put(key, map.get(key));
}
return result;
}
You probably inserted NULL key Strings into the map. This is possible when using a HashMap.
Try to avoid adding NULL keys. Further you could use a TreeMap.
Bye the way it is not bad to iterate over the entry set, you could clean up your code
by using foreach in function2 like you have done in function1:
This will look something like:
for(Entry<String, Float> entry : map.entrySet()) {
Float val = entry.getValue();
}
Although it is not necessary to clean up function2.
But you should find the location where you inserted the NULL key into the map.
function1 uses a foreach loop, which will throw a NullPointerException when the map is null.
You should check the map to be not null before you iterate with foreach
Further You should rewrite the ugly
if("java.lang.String".equalsIgnoreCase(entry.getKey().getClass().getName())) {
to
if (entry.getKey().getClass() == String.class) {