Convert each list to map and merge it (I use Lombok to not write boilerplate code):
@Data
@NoArgsConstructor
@AllArgsConstructor
class Server {
private String name;
private String attribute1;
private String attribute2;
}
public class ServerMain {
public static void main(String[] args) {
List<Server> servers1 = Arrays.asList(
new Server("name1", "attr1.1", null),
new Server("name2", "attr1.2", null));
List<Server> servers2 = Arrays.asList(
new Server("name1", null, "attr2.1"),
new Server("name2", null, "attr2.2"));
Map<String, Server> serverMap1 = servers1.stream().collect(Collectors.toMap(Server::getName, Function.identity()));
Map<String, Server> serverMap2 = servers2.stream().collect(Collectors.toMap(Server::getName, Function.identity()));
serverMap1.keySet().forEach(key -> serverMap1.merge(key,
serverMap2.get(key),
(server1, server2) -> {
server1.setAttribute2(server2.getAttribute2());
return server1;
}));
System.out.println(serverMap1);
}
}
Answer from Dmitry Gorkovets on Stack OverflowConvert each list to map and merge it (I use Lombok to not write boilerplate code):
@Data
@NoArgsConstructor
@AllArgsConstructor
class Server {
private String name;
private String attribute1;
private String attribute2;
}
public class ServerMain {
public static void main(String[] args) {
List<Server> servers1 = Arrays.asList(
new Server("name1", "attr1.1", null),
new Server("name2", "attr1.2", null));
List<Server> servers2 = Arrays.asList(
new Server("name1", null, "attr2.1"),
new Server("name2", null, "attr2.2"));
Map<String, Server> serverMap1 = servers1.stream().collect(Collectors.toMap(Server::getName, Function.identity()));
Map<String, Server> serverMap2 = servers2.stream().collect(Collectors.toMap(Server::getName, Function.identity()));
serverMap1.keySet().forEach(key -> serverMap1.merge(key,
serverMap2.get(key),
(server1, server2) -> {
server1.setAttribute2(server2.getAttribute2());
return server1;
}));
System.out.println(serverMap1);
}
}
For each server in servers1 find a matching server2 in servers2 and set the missing attribute of the first one to correct attribute else if there is no matching server by name simply return null. Also note that this implementation will return only the list of servers name contained in servers1.
@AllArgsConstructor
@Data
private class Server {
private String name;
private String attribute1;
private String attribute2;
}
List<Server> completServersInfo = servers1.stream()
.map((server1 -> {
Server matchingServer = servers2.stream()
.filter(server2 -> server2.name.equals(server1.name))
.findFirst()
.orElse(null);
server1.setAttribute2(matchingServer.attribute2);
return server1;
}))
.collect(Collectors.toList());
In Java 8:
List<String> newList = Stream.concat(listOne.stream(), listTwo.stream())
.collect(Collectors.toList());
Java 16+:
List<String> newList = Stream.concat(listOne.stream(), listTwo.stream()).toList();
Off the top of my head, I can shorten it by one line:
List<String> newList = new ArrayList<String>(listOne);
newList.addAll(listTwo);
Assuming that you want to retain non zero marks and non null status elements, you can not directly use distinct. You can use Collectors.toMap as below,
List<User> userList3 = Stream.concat(source1.stream(), source2.stream())
.collect(Collectors.toMap(e -> e.firstName + e.lastName, e -> e,
(User u1, User u2) -> {
if (u1.marks == 0)
u1.marks = u2.marks;
if (u1.status == null)
u1.status = u2.status;
return u1;
})).values().stream().collect(Collectors.toList());
Note that you may need to reorder elements.
Similar to this answer but here 'User' within source list remains unchanged:
List<User> values = new ArrayList<>(Stream.concat(source1.stream(), source2.stream())
.collect(Collectors.toMap(e -> e.firstName + e.lastName, Function.identity(),
(User u1, User u2) ->
new User(u1.firstName, u1.lastName, u1.count,
(u1.marks == 0) ? u2.marks : u1.marks,
(u1.status == null) ? u2.status : u1.status
)
)).values());
If you are using Jackson (one of the most popular JSON libraries), you can simply achieve this as follows:
Code Snippet
ObjectMapper mepper = new ObjectMapper();
List<Map<String, Object>> listAs400 = mepper.readValue(jsonStrAs400, List.class);
List<Map<String, Object>> listSqlServer = mepper.readValue(jsonStrSqlServer, List.class);
listAs400.forEach(e1 -> {
listSqlServer.forEach(e2 -> {
if (e1.get("truckNumber").toString().equals(e2.get("truckNumber").toString())) {
e2.forEach((k, v) -> {
e1.put(k, v);
});
}
});
});
System.out.println(mapper.writeValueAsString(listAs400));
Console Output
[
{
"assetId":308,
"type":"OV",
"truckNumber":"L122",
"longitude":0,
"latitude":0,
"id":308,
"trailerGroup":"C",
"loaded":false,
"dedicated":false,
"intermodal":false,
"sealed":false,
"companyOwned":true,
"onSite":false,
"customerId":"KTPH",
"modified":{
"when":1546498401156
},
"created":{
"when":1546498401156
}
},
{
"assetId":309,
"type":"PO",
"truckNumber":"SQ46",
"longitude":0,
"latitude":0,
"id":309,
"trailerGroup":"C",
"loaded":false,
"dedicated":false,
"intermodal":false,
"sealed":false,
"companyOwned":true,
"onSite":true,
"customerId":"KTPH",
"modified":{
"when":1546498401156
},
"created":{
"when":1546498401156
}
}
]
Try the example below. I believe this fulfills your requirements of merging your two lists, updating any existing values and finally adding any that are not in the first query.
In addition, I took into consideration that you are using Java Runtime Environment 7(JRE 1.7).
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map.Entry;
import java.util.Set;
import org.json.simple.JSONArray;
import org.json.simple.parser.JSONParser;
import org.json.simple.parser.ParseException;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
public class App {
private static String path1 = "C:\\path\\to\\AS400.json";
private static String path2 = "C:\\path\\to\\SQL_Server_query.json";
public static void main( String[] args ) {
JSONArray trailersAS400 = null;
JSONArray trailersSQLServer = null;
try {
FileReader fr = new FileReader(path1);
FileReader fr2 = new FileReader(path2);
// utilize simple json parser to parse json objects
trailersAS400 = (JSONArray) new JSONParser().parse(fr);
trailersSQLServer = (JSONArray) new JSONParser().parse(fr2);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (ParseException e) {
e.printStackTrace();
}
List<Object> list = new ArrayList<Object>(); // store parsed JSON's data in a list
for (Object trSQL : trailersAS400) {
list.add(trSQL);
}
for (Object tr400 : trailersSQLServer) {
list.add(tr400);
}
HashMap<String, Object> map1 = new HashMap<String, Object>(); // maps truck L122 key value pairs
HashMap<String, Object> map2 = new HashMap<String, Object>(); // maps truck SQ46 key value pairs
for (Iterator iter = list.iterator(); iter.hasNext();) { // iterate through list and update map1 with key value pair.
HashMap<String, Object> truck = (HashMap<String, Object>) iter.next();
if (truck.containsValue("L122")) {
Set<Entry<String, Object>> s = truck.entrySet();
for (Entry<String, Object> entry : s) {
map1.put(entry.getKey(), entry.getValue());
}
} else if (truck.containsValue("SQ46")) { // iterate through list and update map2 with key value pair.
Set<Entry<String, Object>> s = truck.entrySet();
for (Entry<String, Object> entry : s) {
map2.put(entry.getKey(), entry.getValue());
}
}
}
// Update map with map1 & map2. Note the key is represented as the truck number.
HashMap<String, Object> map = new HashMap<String, Object>();
map.put("L122", map1);
map.put("SQ46", map2);
Gson pp = new GsonBuilder().setPrettyPrinting().create();
String p = pp.toJson(map);
System.out.println(p);
}
}
output:
{
"L122": {
"truckNumber": "L122",
"dedicated": false,
"sealed": false,
"created": {
"when": 1546498401156
},
"latitude": 0,
"type": "OV",
"loaded": false,
"intermodal": false,
"companyOwned": true,
"assetId": 308,
"customerId": "KTPH",
"onSite": false,
"modified": {
"when": 1546498401156
},
"trailerGroup": "C",
"id": 308,
"longitude": 0
},
"SQ46": {
"truckNumber": "SQ46",
"dedicated": false,
"sealed": false,
"created": {
"when": 1546498401156
},
"latitude": 0,
"type": "PO",
"loaded": false,
"intermodal": false,
"companyOwned": true,
"assetId": 309,
"customerId": "KTPH",
"onSite": true,
"modified": {
"when": 1546498401156
},
"trailerGroup": "C",
"id": 309,
"longitude": 0
}
}
For the purpose of performance. You may consider using a LinkedHashMap versus a HashMap as is done in the example above. Iterating is more efficient when using a LinkedHashMap. The below example uses this approach.
public class App {
private static String path1 = "C:\\path\\to\\AS400.json";
private static String path2 = "C:\\path\\to\\SQL_Server_query.json";
public static void main( String[] args ) {
JSONArray trailersAS400 = null;
JSONArray trailersSQLServer = null;
try {
FileReader fr = new FileReader(path1);
FileReader fr2 = new FileReader(path2);
// utilize simple json parser to parse json objects
trailersAS400 = (JSONArray) new JSONParser().parse(fr);
trailersSQLServer = (JSONArray) new JSONParser().parse(fr2);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (ParseException e) {
e.printStackTrace();
}
List<Object> list = new ArrayList<Object>(); // store parsed JSON's data in a list
for (Object trSQL : trailersAS400) {
list.add(trSQL);
}
for (Object tr400 : trailersSQLServer) {
list.add(tr400);
}
HashMap<String, Object> map1 = new HashMap<String, Object>(); // maps truck L122 key value pairs
HashMap<String, Object> map2 = new HashMap<String, Object>(); // maps truck SQ46 key value pairs
Iterator<Object> iter = list.iterator();
while (iter.hasNext()) { // iterate through list and update map1 with key value pair.
LinkedHashMap<String, Object> truck = new LinkedHashMap<String, Object>();
truck.putAll((Map<? extends String, ? extends Object>) iter.next());
if (truck.containsValue("L122")) {
Set<Entry<String, Object>> s = truck.entrySet();
for (Entry<String, Object> entry : s) {
map1.put(entry.getKey(), entry.getValue());
}
} else if (truck.containsValue("SQ46")) { // iterate through list and update map2 with key value pair.
Set<Entry<String, Object>> s = truck.entrySet();
for (Entry<String, Object> entry : s) {
map2.put(entry.getKey(), entry.getValue());
}
}
}
// Update map with map1 & map2. Note the key is represented as the truck number.
HashMap<String, Object> map = new HashMap<String, Object>();
map.put("L122", map1);
map.put("SQ46", map2);
Gson pp = new GsonBuilder().setPrettyPrinting().create();
String p = pp.toJson(map);
System.out.println(p);
}
}
Both example code will produce your desired results as indicted in the above output.