简体   繁体   中英

Merge two lists with common key in Java

I am getting one list from an AS400 query and another from a SQL Server query. I need to merge these two lists into a single list. The first list is every asset in our inventory and looks like this:

[
    {
        "assetId": 0,
        "type": "OV",
        "truckNumber": "L122",
        "longitude": 0,
        "latitude": 0,
        "id": 0
    },
    {
        "assetId": 0,
        "type": "PO",
        "truckNumber": "SQ46",
        "longitude": 0,
        "latitude": 0,
        "id": 0
    }
]

The second list has more detail and looks like this, with both lists having one field in common, truckNumber:

[
   {
        "trailerGroup": "C",
        "assetId": 308,
        "loaded": false,
        "dedicated": false,
        "intermodal": false,
        "sealed": false,
        "truckNumber": "L122",
        "companyOwned": true,
        "onSite": false,
        "customerId": "KTPH",
        "id": 308,
        "modified": {
            "when": 1546498401156
        },
        "created": {
            "when": 1546498401156
        }
    },
    {
        "trailerGroup": "C",
        "assetId": 309,
        "loaded": false,
        "dedicated": false,
        "intermodal": false,
        "sealed": false,
        "truckNumber": "SQ46",
        "companyOwned": true,
        "onSite": true,
        "customerId": "KTPH",
        "id": 309,
        "modified": {
            "when": 1546498401156
        },
        "created": {
            "when": 1546498401156
        }
    }
]

I need to update any existing values like longitude while adding any that are not in the first query.

I tried some of the merge examples but none work at all or others just append the first list to the second list.


Possible Solution:

Anyone see an issue with this?

List<Trailer> trailers = null;
List<Trailer> trailersAS400 = null;
List<Trailer> trailersSQLServer = null;

try {
    trailersAS400 = getTrailerAS400Proxy().getTrailers();
    trailersSQLServer = getTrailerSQLServerProxy().getTrailers();           

    Map<String, Trailer> map = new HashMap<>();
    for (Trailer t : trailersAS400) {
        map.put(t.getNumber(), t);
    }
    for (Trailer t : trailersSQLServer) {
        String key = t.getNumber();
        if (map.containsKey(key)) {
            map.get(key).setNumber(t.getNumber());
        } else {
            map.put(key, t);
        }
    }
    trailers = new ArrayList<>(map.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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM