Convert Map<String, ArrayList<String>> to Nested JSON - java

So I have a Map<String, ArrayList> parentToChild and want to create basically a "Family Tree" or nested hierarchy. Below is an example of the map but there could be more children at each level e.g. (Claire could have Matt and Bruce as children):
David -> [Claire]
Claire -> [Matt]
Matt -> [Sean, Terry]
I know the root of the tree should be David for the above example and it will only have one root.
Example output
{
"David": {
"Claire": {
"Matt": {
"Sean": {},
"Terry": {}
}
}
}
}
I've tried few things but genuinely stumped.
EDIT: Code tried so far
public Set<Tree> transform(Map<String, ArrayList<String>> input) {
Set<String> roots = new HashSet<String>(input.keySet());
Map<String, Tree> map = new HashMap<String, Tree>();
for (Map.Entry<String, ArrayList<String>> entry : input.entrySet()) {
String key = entry.getKey();
List<String> childKeys = entry.getValue();
Tree tree = map.get(key);
if (tree == null) {
tree = new Tree(key);
map.put(key, tree);
}
for (String childKey : childKeys) {
roots.remove(childKey);
Tree child = map.get(childKey);
if (child == null) {
child = new Tree(childKey);
map.put(childKey, child);
}
tree.addChild(child);
}
}
Set<Tree> res = new HashSet<Tree>(roots.size());
for (String key : roots) {
res.add(map.get(key));
}
return res;
}
Tree class:
public class Tree {
private String key;
private Tree child;
public Tree(String key){
this.key = key;
}
public void addChild(Tree child){
this.child = child;
}
}
The issue is when I use this code the output (What is in the set after debugging/printing) I get is
David:
Claire:
Matt:
Terry:

You could use a Map<String,Object>:
private static final Gson GSON = new GsonBuilder()
.setPrettyPrinting()
.create();
public static void main(String[] args) {
Map<String, List<String>> input = new HashMap<>();
input.put("David", Arrays.asList("Claire"));
input.put("Claire", Arrays.asList("Matt"));
input.put("Matt", Arrays.asList("Sean", "Terry"));
Map<String,Object> result = new HashMap<>();
convert(input, "David", result);
GSON.toJson(result, System.out);
}
private static void convert(Map<String, List<String>> input, String root,
Map<String,Object> result) {
if (!result.containsKey(root)) {
Map<String,Object> rootObj = new HashMap<>();
result.put(root, rootObj);
List<String> children = input.get(root);
if (children != null) {
for (String child: children) {
convert(input, child, rootObj);
}
}
}
}
Output:
{
"David": {
"Claire": {
"Matt": {
"Terry": {},
"Sean": {}
}
}
}
}

In the Java world you have access to Saxon 9.8 or later HE where XPath 3.1 or XQuery 3.1 or XSLT 3.0 all have support for representing your initial map as an XdmMap and processing them, for instance with XQuery:
declare namespace map = "http://www.w3.org/2005/xpath-functions/map";
declare namespace output = "http://www.w3.org/2010/xslt-xquery-serialization";
declare option output:method 'json';
declare option output:indent 'yes';
declare variable $map as map(xs:string, array(xs:string)) external := map {
'David' : [ 'Claire' ],
'Claire' : [ 'Matt' ],
'Matt' : [ 'Sean', 'Terry' ]
};
declare variable $root as xs:string external := 'David';
declare function local:create-tree($map as map(xs:string, array(xs:string)), $children as xs:string*) as map(*) {
map:merge($children ! map { . : local:create-tree($map, $map(.)) })
};
local:create-tree($map, $root)
https://xqueryfiddle.liberty-development.net/3Nzd8bV
A simple Java example to run this with Saxon 10 HE (its API documentation is at http://saxonica.com/html/documentation/using-xquery/api-query/s9api-query.html), passing a Java Map to the XQuery (inserted inline as a string but could of course be loaded from a file instead) is:
import java.util.HashMap;
import java.util.Map;
import net.sf.saxon.s9api.Processor;
import net.sf.saxon.s9api.QName;
import net.sf.saxon.s9api.SaxonApiException;
import net.sf.saxon.s9api.XQueryCompiler;
import net.sf.saxon.s9api.XQueryEvaluator;
import net.sf.saxon.s9api.XQueryExecutable;
import net.sf.saxon.s9api.XdmMap;
public class SaxonJavaMapToNestedJSONObject {
public static void main(String[] args) throws SaxonApiException {
Map<String, String[]> map = new HashMap<>();
map.put("David", new String[] { "Claire" });
map.put("Claire", new String[] { "Matt" });
map.put("Matt", new String[] { "Sean", "Terry" });
Processor processor = new Processor(true);
XQueryCompiler compiler = processor.newXQueryCompiler();
XQueryExecutable executable = compiler.compile("declare namespace map = \"http://www.w3.org/2005/xpath-functions/map\";\n" +
"\n" +
"declare namespace output = \"http://www.w3.org/2010/xslt-xquery-serialization\";\n" +
"\n" +
"declare option output:method 'json';\n" +
"declare option output:indent 'yes';\n" +
"\n" +
"declare variable $map as map(xs:string, array(xs:string)) external;\n" +
"\n" +
"declare variable $root as xs:string external := 'David';\n" +
"\n" +
"declare function local:create-tree($map as map(xs:string, array(xs:string)), $children as xs:string*) as map(*) {\n" +
" map:merge($children ! map { . : local:create-tree($map, $map(.)) })\n" +
"};\n" +
"\n" +
"local:create-tree($map, $root)");
XQueryEvaluator evaluator = executable.load();
evaluator.setExternalVariable(new QName("map"), XdmMap.makeMap(map));
evaluator.run(processor.newSerializer(System.out));
}
}
Of course you could set the root variable as well from Java: evaluator.setExternalVariable(new QName("root"), new XdmAtomicValue("David"));

Related

How to put an Ontology in Javafx TreeView with OWL API?

I tried first to put all Classe(key) and SuperClasses(value :ArrayList, direct superClasses) of the ontology (I want that the last element of the ontology be the root of my treeView) in a HashMap (hm).
However I don't know how to put properly this hashmap in a TreeView.
A recursive tree would suit much better but I don't know how to do that. (I have a method who convert a recursive data structure in a treeView)
Would anyone be able to give me some clues for my problem?
Thanks !
method who return the hashmap :
public HashMap<String, ArrayList<String>> getClassesHashMap() {
HashMap<String, ArrayList<String>> hm = new HashMap<String, ArrayList<String>>();
OWLReasonerFactory reasonerFactory = new StructuralReasonerFactory();
OWLReasoner reasonerFactory3 = reasonerFactory.createReasoner(ontology);
OWLDataFactory fac3 = ontology.getOWLOntologyManager().getOWLDataFactory();
for (String s : getClassesName()) {
IRI docIRI = IRI.create(ontology.getOntologyID().getOntologyIRI().get() + "#" + s);
OWLClass pizza = fac3.getOWLClass(docIRI);
NodeSet<OWLClass> subClses = reasonerFactory3.getSuperClasses(pizza, true);
Set<OWLClass> clses = subClses.getFlattened();
System.out.println("Subclasses of " + s + " : ");
//instanciate the hashmap
for (OWLClass cls1 : clses) {
//cls1.getIRI().getShortForm() is the name of an ontology classes in String
//all the classe is a key, and their superclasses is the value
if (!cls1.getIRI().getShortForm().equals("Thing")) {
if (!hm.containsKey(s)) {
hm.put(s, new ArrayList<String>());
}
hm.get(s).add(cls1.getIRI().getShortForm());
System.out.println(" " + cls1.getIRI().getShortForm());
}
System.out.println();
}
}
// Tree<String> res = new Tree<String>("");
return hm;
}
Method who instanciate the TreeView
private void initTreeView() throws OWLException {
// TreeItem<String> root = new TreeItem<String>("Private_Policy");
tree.setFixedCellSize(25);
//Privacy Policy is the Ontology classe I Use
TreeItem<String> root = new TreeItem<String>("PrivacyPolicy");
root.setExpanded(true);
OntologieDAO ont = new OntologieDAO("WotPriv.owl");
//hashmap of the ontology
HashMap<String, ArrayList<String>> hm = ont.getClassesHashMap();
TreeItem<String> children = new TreeItem<String>("");
System.out.println(hm);
int i = 0;
//work only for my ontology
for (String s : hm.get(root.getValue())) {
TreeItem<String> tI = new TreeItem<String>(s);
root.getChildren().add(tI);
if (hm.containsKey(s)) {
for (String s1 : hm.get(s)) {
TreeItem<String> n = new TreeItem<String>(s1);
TreeItem<String> tI1=root.getChildren().get(root.getChildren().indexOf(tI));
tI1.getChildren().add(n);
if (hm.containsKey(s1)) {
for (String s2 : hm.get(s1)) {
tI1.getChildren().get(tI1.getChildren().indexOf(n)).getChildren().add(new TreeItem<String>(s2));
}}
}
}
}
tree.setRoot(root);
tree.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);
System.out.println(ont.getClassesName());
}
A recursive data structure and a method to convert it in treeview :
import java.util.HashSet;
import java.util.Set;
public class MyType<N> {
private Set<MyType<N>> children = new HashSet<>();
private N Value;
public MyType(N value) {
super();
Value = value;
}
public Set<MyType<N>> getChildren() {
return children;
}
public void setChildren(Set<MyType<N>> children) {
this.children = children;
}
public N getValue() {
return Value;
}
public void setValue(N value) {
Value = value;
}
}
private TreeItem<MyType<String>> buildSubtree(MyType<String> root) {
TreeItem<MyType<String>> result = new TreeItem<>(root);
if (root.getChildren() != null) {
for (MyType<String> child : root.getChildren()) {
result.getChildren().add(buildSubtree(child));
}
}
return result;
}
(Image) Result I want to have (I already have it but my code is really dirty and would'nt work with other ontology)

How to parse JSON without POJO

This is my json:
{
"taggedEntries": {
"user/f8cf24ef-4bd0-846f-a11a781ce81a/tag/TEST": [
"20HQtzLrqRe8xz8tybYf2aS087xS92Zi_1719877dbea:8e4:6eb16f2b"
],
"user/f8cf24ef-4bd0-846f-a11a781ce81a/tag/global.unsaved": [
"360ebRQH+hi4mCv/YibdkukUtv175h4JfU23PTw2O8M=_171888f776b:69cb:f8e58482",
"20HQtzL4prqRe8xz8tybYf2aS087xS92Zi+zuo=_171987c5e49:8ed:6eb16f2b",
"20HQtzL4rqRe8xz8tybYf2aS087xS92Zi+zuo=_171987d5d3d:8ee:6eb16f2b",
"20HQtzL4q9uNe8xz8tybYf2aS087xS92Zi+zuo=_1719854c09a:8bd:6eb16f2b"
],
"user/f8cf24ef-4bd0-846f-a11a781ce81a/tag/286f1f46-911c-4bc2-4b028b0d7ed0": [
"v1I7ZIsSoGZxr80NFebazQf2J2QviXCcdot3TOU=_1717e68bf58:fcd1:75b51987",
"360ebRQH+hibdkukUtv175h4JfU23PTw2O8M=_171888f776b:69cb:f8e58482",
"20HQtzL4q9uqRe8xz8tybYf2aS087xS92Zi+zuo=_171983b3399:8b7:6eb16f2b"
]
}
}
How can I parse it?
I would like to get the following structure
TaggedEntries<String, Array<String>>
where:
1 argument is tag name, 2 argument is ids tag
Tag name is a dynamic string. I can't get as static element of json.
Any idea?
Thanks for help :)
Parse to Map<String, Map<String, List<String>>> then call get("taggedEntries") to get the Map<String, List<String>> value you're looking for.
In your TaggedEntries class you should have HashMap>. I think your argument without POJO is hard or messy I think. You'll play with alot of JsonObject / JsonArray.
My solution:
val obj = JsonParser().parse(jsonStr).asJsonObject.getAsJsonObject("taggedEntries")
val entries = obj.entrySet() //will return members of your object
val data = mutableMapOf<String,ArrayList<String>>()
for ((key) in entries) {
val ids: JsonArray = obj.getAsJsonArray(key)
val listIdTags = arrayListOf<String>()
ids.forEach{
listIdTags.add(it.toString())
}
data.put(key,listIdTags)
}
// Print Data
data.forEach(){ key, value ->
println("Key: $key")
println("Value:")
value.forEach{
println( it)
}
}
Maybe there is a better solution but I haven't found it. If you have a solution I'd like to hear it.
When you need some special things, you may need some special handiwork to be done and this isn't a rocket science, really :) For example, using a tiny JSON parser
https://github.com/anatolygudkov/green-jelly:
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
public class ParseMyJson {
private static final String myJson = "{" +
"\"taggedEntries\": {" +
"\"user/f8cf24ef-4bd0-846f-a11a781ce81a/tag/TEST\": [" +
"\"20HQtzLrqRe8xz8tybYf2aS087xS92Zi_1719877dbea:8e4:6eb16f2b\"]," +
"\"user/f8cf24ef-4bd0-846f-a11a781ce81a/tag/global.unsaved\": [" +
"\"360ebRQH+hi4mCv/YibdkukUtv175h4JfU23PTw2O8M=_171888f776b:69cb:f8e58482\"," +
"\"20HQtzL4prqRe8xz8tybYf2aS087xS92Zi+zuo=_171987c5e49:8ed:6eb16f2b\"," +
"\"20HQtzL4rqRe8xz8tybYf2aS087xS92Zi+zuo=_171987d5d3d:8ee:6eb16f2b\"," +
"\"20HQtzL4q9uNe8xz8tybYf2aS087xS92Zi+zuo=_1719854c09a:8bd:6eb16f2b\"" +
"]," +
"\"user/f8cf24ef-4bd0-846f-a11a781ce81a/tag/286f1f46-911c-4bc2-4b028b0d7ed0\": [" +
"\"v1I7ZIsSoGZxr80NFebazQf2J2QviXCcdot3TOU=_1717e68bf58:fcd1:75b51987\"," +
"\"360ebRQH+hibdkukUtv175h4JfU23PTw2O8M=_171888f776b:69cb:f8e58482\"," +
"\"20HQtzL4q9uqRe8xz8tybYf2aS087xS92Zi+zuo=_171983b3399:8b7:6eb16f2b\"" +
"]" +
"}" +
"}";
public static void main(String[] args) {
final TaggedEntries<String, String> result = new TaggedEntries<>();
final JsonParser parser = new JsonParser();
parser.setListener(
new JsonParserListenerAdaptor() {
private String lastPropertyName = null;
private boolean inArray = false;
public boolean onObjectMember(final CharSequence name) {
lastPropertyName = name.toString();
return true;
}
#Override
public boolean onArrayStarted() {
inArray = true;
result.onTag(lastPropertyName);
return true;
}
#Override
public boolean onArrayEnded() {
inArray = false;
return true;
}
#Override
public boolean onStringValue(final CharSequence data) {
if (inArray) {
result.onValue(data.toString());
}
return true;
}
}
);
parser.parse(myJson);
parser.eoj();
System.out.println(result);
}
public static class TaggedEntries<T, V> {
private final Map<T, List<V>> allEntries = new HashMap();
private List<V> currentTagValues;
public TaggedEntries() {
}
public void onTag(final T tag) {
currentTagValues = new ArrayList<>();
allEntries.put(tag, currentTagValues);
}
public void onValue(final V value) {
if (currentTagValues == null) {
throw new IllegalStateException("onTag must be called before");
}
currentTagValues.add(value);
}
public List<V> tagValues(final T tag) {
return allEntries.get(tag);
}
public Set<T> tags() {
return allEntries.keySet();
}
#Override
public String toString() {
final StringBuilder result = new StringBuilder("TaggedEntries{\n");
allEntries.forEach((t, vs) -> {
result.append('\t').append(t).append('\n');
vs.forEach(v -> result.append("\t\t").append(v).append('\n'));
});
result.append('}');
return result.toString();
}
}
}

How to define array of objects in a properties file and read from Java program

I have a properties file like this.
property[0].name=A
property[0].value=1
property[1].name=B
property[1].value=2
property[2].name=C
property[2].value=3
How to read this file as a list of objects of a class {name, value} in plain java program using ResourceBundle or Properties?
Here is the class.
public class XYZ {
private String name;
private String value;
// Getters & Setters
}
I need to get like this.
ArrayList<XYZ> propertiesList = SomeUtility.getProperties("property", XYZ.class);
Utility class might be like this.
public class SomeUtility {
public static ArrayList getProperties(String key, Class cls) {
//logic
}
}
I might not understand exactly what you want so feel free to correct me and give me more constraints to work with but here is a simple way to read a Properties file located somewhere in your project:
private static void readPropertiesFile(String path) throws IOException {
java.util.Map<String, String> map = new java.util.LinkedHashMap<>();
Properties properties = new Properties();
InputStream inputStream = new FileInputStream(path);
properties.load(inputStream);
for (String name : properties.stringPropertyNames()) {
map.put(name, properties.getProperty(name));
}
for (java.util.Map.Entry<String, String> entry : map.entrySet()) {
System.out.printf("Property Key: %s, Property Value: %s%n", entry.getKey(), entry.getValue());
}
}
Output
Property Key: property[0].name, Property Value: A
Property Key: property[1].name, Property Value: B
Property Key: property[0].value, Property Value: 1
Property Key: property[1].value, Property Value: 2
Property Key: property[2].name, Property Value: C
Property Key: property[2].value, Property Value: 3
This is the solution I wrote, but it involves Reflect and Gson. Is there any better way to do this? Anything already available which is fine tuned like Apache's.
import com.google.gson.Gson;
import com.google.gson.JsonObject;
import java.lang.reflect.Field;
import java.util.*;
public class ListResourceBundle {
public static final Gson gson = new Gson();
private final ResourceBundle bundle;
public ListResourceBundle(ResourceBundle bundle) {
this.bundle = bundle;
}
public List<?> getProperties(String key, Class<?> cls) {
final int maxArraySize = getMaxArraySize(key, getMatchingKeys(key));
final List<String> fields = getFields(cls);
final List<Object> result = new ArrayList<>();
for (int i = 0; i < maxArraySize; i++) {
JsonObject jsonObject = new JsonObject();
for (String field : fields) {
jsonObject.addProperty(field, getStringOrNull(key + "[" + i + "]." + field));
}
result.add(gson.fromJson(jsonObject, cls));
}
System.out.println("result.toString() = " + result.toString());
return result;
}
public List<String> getMatchingKeys(String key) {
Enumeration<String> keys = bundle.getKeys();
List<String> matchingKeys = new ArrayList<>();
while(keys.hasMoreElements()) {
String k = keys.nextElement();
if(k.startsWith(key)) {
matchingKeys.add(k);
}
}
Collections.sort(matchingKeys);
return matchingKeys;
}
public int getMaxArraySize(String key, List<String> matchingKeys) {
int maxArraySize = 0;
for (int i = 0; ; i++) {
boolean indexAvailable = false;
for (String matchingKey : matchingKeys) {
if(matchingKey.startsWith(key + "[" + i + "]")) {
indexAvailable = true;
break;
}
}
if(indexAvailable) {
maxArraySize++;
} else {
break;
}
}
return maxArraySize;
}
public String getStringOrNull(String key) {
try {
return bundle.getString(key);
} catch (MissingResourceException e) {
return null;
}
}
public List<String> getFields(Class<?> cls) {
final List<String> fields = new ArrayList<>();
for (Field field : cls.getDeclaredFields()) {
fields.add(field.getName());
}
return fields;
}
public static void main(String[] args) {
ResourceBundle bundle = ResourceBundle.getBundle("com.example.application.resources.Resource");
ListResourceBundle applicationResourceBundle = new ListResourceBundle(bundle);
applicationResourceBundle.getProperties("property", ReportParam.class);
}
}
Resource:
property[0].name=A
property[0].value=1
property[1].name=B
property[1].value=2
property[2].name=C
property[2].value=3
Output:
result.toString() = [
ReportParam{name='A', value='1'},
ReportParam{name='B', value='2'},
ReportParam{name='C', value='3'}]
Process finished with exit code 0
I know it's bit late of an answer, but if I understand your problem statement correctly, you can use :
#ConfigurationProperties
to get your job done.
Here is my spring-boot example with a YAML file for the sake of convenience (same can be achieved through properties file as well).
application.yaml:
xyz:
xyzprops :
-
name: cbc
value: 441
-
name: obc
value: 443
XYZ class:
#Component
#ConfigurationProperties(prefix = "xyz")
public class XYZ{
private List<XYZProps> xyzprops;
public List<XYZProps> getXyzprops() {
return xyzprops;
}
public void setXyzprops(List<XYZProps> xyzprops) {
this.xyzprops = xyzprops;
}
public class XYZProps{
String name;
String value;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
}
}
And then #Autowire XYZ where you want to use it.
I would use JSON:
in your file:
property=[{"name":"A","value":"1"},{"name":"B","value":"2"},{"name":"C","value":"3"}]
and then deserialize it using com.google.gson.gson (or any other) library:
ArrayList<XYZ> propertiesList;
propertiesList = new gsonbuilder().create().fromjson(property, propertiesList.class);
NOTE: I haven't tested this code, and i'm not very familiar with java so i am sure there is a better,cleaner way to implement this.

Merge three HashMap<String, POJO> with unique key

I have three HashMap of this generic type HashMap<String,Server> but I want to combine the data of all the HashMap based on my unique key. But only Server pojo has different data.
So first hashmap has some servers information like ip_address and server name therefore I have both values in map and ip_address as key. Then I have some other hardware spec stored in other map and ip_address as key and so same in third map.
Therefore, combining all POJO based on key I will get complete server information with corresponding ip_address.
I don't know how to do it without doing nested operation
Here is a way to do this. I have shown the example code using only two Map collections, and, the third can be applied in similar way.
I am using Map's computeIfPresent method to "merge" the values of the two maps. The BiFunction (the argument for the computeIfPresent) need to take care of the "merging" aspect - any validations, etc., presently not known (to me). Also, see the note below on computeIfPresent.
Example code:
import java.util.*;
import java.util.function.*;
public class CombiningMaps {
private static Map<String, ServerInfo> map1 = new HashMap<>();
private static Map<String, ServerInfo> map2 = new HashMap<>();
private static BiFunction<String, ServerInfo, ServerInfo> combineWithMap2 =
(k, v) -> {
if (map2.get(k) != null) {
ServerInfo v2 = map2.get(k);
// combine values of map1 and map2
v.setHw2(v2.getHw2());
}
return v;
};
public static void main(String [] args) {
// Add some test data to map 1
map1.put("serv1", new ServerInfo("0A", "a1", "",""));
map1.put("serv2", new ServerInfo("0B", "b1", "",""));
map1.put("serv3", new ServerInfo("0C", "c1", "",""));
System.out.println(map1);
// Add some data to map 2
map2.put("serv1", new ServerInfo("0A", "", "a2",""));
map2.put("serv2", new ServerInfo("0B", "", "b2",""));
map2.put("serv3", new ServerInfo("0C", "", "c2",""));
System.out.println(map2);
// Update map1 with map 2's info
map1.forEach((k,v) -> map1.computeIfPresent(k, combineWithMap2));
System.out.println(map1);
}
}
class ServerInfo {
private String ipAddr;
private String hw1; // hw stands for hardware related info
private String hw2;
private String hw3;
public ServerInfo(String ipAddr, String hw1, String hw2, String hw3) {
this.ipAddr = ipAddr;
this.hw1 = hw1;
this.hw2 = hw2;
this.hw3 = hw3;
}
public String getIpAddr() {
return ipAddr;
}
public String getHw1() {
return hw1;
}
public void setHw1(String s) {
hw1 = s;
}
public String getHw2() {
return hw2;
}
public void setHw2(String s) {
hw2 = s;
}
public String getHw3() {
return hw3;
}
public void setHw3(String s) {
hw3 = s;
}
public String toString() {
return ipAddr + ":" + hw1 + "-" + hw2 + "-" + hw3;
}
}
The output:
{serv2=0B:b1--, serv3=0C:c1--, serv1=0A:a1--}
{serv2=0B:-b2-, serv3=0C:-c2-, serv1=0A:-a2-}
{serv2=0B:b1-b2-, serv3=0C:c1-c2-, serv1=0A:a1-a2-}
How the computeIfPresent behaves (some scenarios):
Consider a Map<String, Integer> map with keys and values: {four=4, one=1, ten=10, two=2, three=3, five=5, eleven=11, twelve=null}
(1) updates the mapping with new value (note the lambda is a BiFunction returning a newly computed value):
map.computeIfPresent("ten", (k, v) -> new Integer(100));
(2) the function returns a null, the existing mapping is removed:
map.computeIfPresent("eleven", (k, v) -> null);
(3) the mapping is not added, as there is no existing mapping:
map.computeIfPresent("twenty", (k, v) -> new Integer(20));
(4) the existing value is null, so there is no change:
map.computeIfPresent("twelve", (k, v) -> new Integer(12));
After getting all values in three maps I used finalMap to combine values. Here is the working for it since the key is same in all map therefore getting key of map using key of
map1 was a good idea.
Set<Map.Entry<String, Server>> set1 = map.entrySet();
for (Map.Entry<String, Server> me : set1) {
Server server=new Server();
server.setIp_Address(me.getKey());
server.setServerName(me.getValue().getServerName());
server.setOsName(map1.get(me.getKey()).getOsName());
server.setOsVersion(map1.get(me.getKey()).getOsVersion());
server.setOsArchitecture(map1.get(me.getKey()).getOsArchitecture());
server.setHardDiskCapacity(map1.get(me.getKey()).getHardDiskCapacity());
server.setRamCapacity(map1.get(me.getKey()).getRamCapacity());
server.setAvgNetWorkUtilizationSent(map2.get(me.getKey()).getAvgNetWorkUtilizationSent());
server.setAvgNetworkUtilizationReceived(map2.get(me.getKey()).getAvgNetworkUtilizationReceived());
server.setAvgCPUtilization(map2.get(me.getKey()).getAvgCPUtilization());
server.setAvgRamUtilization(map2.get(me.getKey()).getAvgRamUtilization());
finalMap.put(me.getKey(), server);
}
Set<Map.Entry<String, Server>> set2 = finalMap.entrySet();
for (Map.Entry<String, Server> me : set2) {
System.out.println(" ServerIP : "+ me.getValue().getIp_Address()+"\t"+" Server Name :"+me.getValue().getServerName()+"\t \t"+" Hardware Capacity :"+me.getValue().getHardDiskCapacity()+"\t"+" Average CPU Utlization: "+me.getValue().getAvgCPUtilization());
}
Use putAll():
Map<String, Server> all = new HashMap<>();
all.putAll(map1);
all.putAll(map2);
all.putAll(map3);
If you want a one-liner:
Map<String, Server> all = Stream.of(map1, map2, map3)
.reduce(new HashMap<>(), (a, b) -> {a.putAll(b); return a;});
Collisions result in replacement.
Your problem it to merge two POJO classes.
For example
class Server {
private String ipAddr;
private String hw1;
private String hw2;
private String hw3;
//Getter and Setters
}
Server s1 = new Server("0A", "a1", null, null);
Server s2 = new Server("0A", null, "b2", null);
So the merged pojo should be like this.
Server merged = merge(s1, s2);// Server{ipAddr=0A, hw1=a1, hw2=b2, hw3=null}
The merge function looks like this...
public static Server merge(Server s1, Server s2) throws Exception {
Server merged = new Server();
for (Field field : Server.class.getDeclaredFields()) {
field.setAccessible(true);
Object getS1 = field.get(s1);
Object getS2 = field.get(s2);
if(getS1 == null && getS2 != null) {
field.set(merged, getS2);
} else if (getS1 != null && getS2 == null) {
field.set(merged, getS1);
} else { //equal values
field.set(merged, getS1);
}
}
return merged;
}
Here is the example code to merge three maps, Its kinda quick and dirty but works well.
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;
class MergeMaps {
public static void main(String[] args) throws Exception {
Map<String, Server> map1 = new HashMap<>();
Map<String, Server> map2 = new HashMap<>();
Map<String, Server> map3 = new HashMap<>();
// Add some test data to map 1
map1.put("serv1", new Server("0A", "a1", null, null));
map1.put("serv2", new Server("0B", "b1", null, null));
System.out.println(map1);
// Add some data to map 2
map2.put("serv1", new Server("0A", null, "a2", null));
map2.put("serv2", new Server("0B", null, "b2", null));
map2.put("serv3", new Server("0C", null, "c2", null));
System.out.println(map2);
// Add some data to map 3
map3.put("serv1", new Server("0A", null, null, "a3"));
map3.put("serv2", new Server("0B", null, null, "b3"));
map3.put("serv3", new Server("0C", null, null, "c3"));
map3.put("serv4", new Server("0D", null, null, "d4"));
System.out.println(map3);
Map<String, Server> resultingMap = new HashMap<>();
resultingMap.putAll(map1);
for (Map.Entry<String, Server> entry : map2.entrySet()) {
if (resultingMap.containsKey(entry.getKey())) {
Server s = resultingMap.get(entry.getKey());
Server t = entry.getValue();
Server merged = merge(s, t);
resultingMap.put(entry.getKey(), merged);
} else {
resultingMap.put(entry.getKey(), entry.getValue());
}
}
for (Map.Entry<String, Server> entry : map3.entrySet()) {
if (resultingMap.containsKey(entry.getKey())) {
Server server1 = resultingMap.get(entry.getKey());
Server server2 = entry.getValue();
Server merged = merge(server1, server2);
resultingMap.put(entry.getKey(), merged);
} else {
resultingMap.put(entry.getKey(), entry.getValue());
}
}
System.out.println(resultingMap);
}
public static Server merge(Server s1, Server s2) throws Exception {
Server merged = new Server();
for (Field field : Server.class.getDeclaredFields()) {
field.setAccessible(true);
Object getS1 = field.get(s1);
Object getS2 = field.get(s2);
if (getS1 == null && getS2 != null) {
field.set(merged, getS2);
} else if (getS1 != null && getS2 == null) {
field.set(merged, getS1);
} else {
field.set(merged, getS1);
}
}
return merged;
}
}
class Server {
private String ipAddr;
private String hw1;
private String hw2;
private String hw3;
public Server() {
}
public Server(String ipAddr, String hw1, String hw2, String hw3) {
this.ipAddr = ipAddr;
this.hw1 = hw1;
this.hw2 = hw2;
this.hw3 = hw3;
}
//Getter and setters
#Override
public String toString() {
return "Server{" + "ipAddr=" + ipAddr + ", hw1=" + hw1 + ", hw2=" + hw2 + ", hw3=" + hw3 + '}';
}
}
The output looks like this..
{serv2=Server{ipAddr=0B, hw1=b1, hw2=null, hw3=null}, serv1=Server{ipAddr=0A, hw1=a1, hw2=null, hw3=null}}
{serv2=Server{ipAddr=0B, hw1=null, hw2=b2, hw3=null}, serv3=Server{ipAddr=0C, hw1=null, hw2=c2, hw3=null}, serv1=Server{ipAddr=0A, hw1=null, hw2=a2, hw3=null}}
{serv2=Server{ipAddr=0B, hw1=null, hw2=null, hw3=b3}, serv3=Server{ipAddr=0C, hw1=null, hw2=null, hw3=c3}, serv4=Server{ipAddr=0D, hw1=null, hw2=null, hw3=d4}, serv1=Server{ipAddr=0A, hw1=null, hw2=null, hw3=a3}}
{serv2=Server{ipAddr=0B, hw1=b1, hw2=b2, hw3=b3}, serv3=Server{ipAddr=0C, hw1=null, hw2=c2, hw3=c3}, serv4=Server{ipAddr=0D, hw1=null, hw2=null, hw3=d4}, serv1=Server{ipAddr=0A, hw1=a1, hw2=a2, hw3=a3}}

How to copy value from one list to another list having different objects

I have MaterailInfo and StyleInfo, I want to set styleDescription based on StyleNumber matching with materialNumber. I am using 2 for loops, is there any alternative solution?
MaterailInfo:
class MaterailInfo {
private String materialNumber;
private String materialDescription;
public MaterailInfo(String materialNumber, String materialDescription) {
this.materialNumber = materialNumber;
this.materialDescription = materialDescription;
}
// getter setter methods
}
StyleInfo:
class StyleInfo {
private String StyleNumber;
private String styleDescription;
public StyleInfo(String styleNumber, String styleDescription) {
StyleNumber = styleNumber;
this.styleDescription = styleDescription;
}
// getter setter toString methods
}
TEst12:
public class TEst12 {
public static void main(String[] args) {
List<MaterailInfo> mList = new ArrayList<MaterailInfo>();
mList.add(new MaterailInfo("a", "a-desc"));
mList.add(new MaterailInfo("b", "b-desc"));
mList.add(new MaterailInfo("c", "c-desc"));
List<StyleInfo> sList = new ArrayList<StyleInfo>();
sList.add(new StyleInfo("a", ""));
sList.add(new StyleInfo("b", ""));
sList.add(new StyleInfo("c", ""));
for (MaterailInfo m : mList) {
for (StyleInfo s : sList) {
if (s.getStyleNumber().equals(m.getMaterialNumber())) {
s.setStyleDescription(m.getMaterialDescription());
}
}
}
System.out.println(sList);
}
}
If you use a Map instead of a List to store your data, you can get away with doing only a single loop:
Map<String, String> mMap = new HashMap<String, String>();
mMap.put("a", "a-desc");
mMap.put("b", "b-desc");
mMap.put("c", "c-desc");
Map<String, String> sMap = new HashMap<String, String>();
sMap.put("a", "");
sMap.put("b", "");
sMap.put("c", "");
for (Map.Entry<String, String> entry : mMap.entrySet()) {
sMap.put(entry.getKey(), mMap.get(entry.getKey());
}
This code will leave the style description empty if the style number does not match any known material number.
If your numbers can't have duplicates, using a HashMap instead of classes can be a bit faster.
import java.io.*;
import java.util.*;
import java.util.Map.Entry;
public class Demo {
public static void main(String[] args) {
HashMap<String, String> mList = new HashMap();
HashMap<String, String> sList = new HashMap();
mList.put("a", "a-desc");
mList.put("b", "b-desc");
mList.put("c", "c-desc");
sList.put("a", "");
sList.put("b", "");
sList.put("c", "");
Iterator entries = sList.entrySet().iterator();
while (entries.hasNext()) {
Entry entry = (Entry) entries.next();
if (mList.containsKey(entry.getKey())) {
sList.put((String) entry.getKey(), mList.get(entry.getKey()));
}
}
for (Map.Entry<String, String> entry : sList.entrySet()) {
System.out.println(entry.getKey() + " " + entry.getValue());
}
}
}
You can do this using one for loop like this
for (int i = 0; i < mList.size(); i++) {
sList.get(i).setStyleDescription(mList.get(i).getMaterialDescription());
}
Note: i am assuming you have balanced lists in term of size.

Categories