【问题标题】:Merge two lists with common key in Java用Java中的公共键合并两个列表
【发布时间】:2019-01-04 15:40:04
【问题描述】:

我从 AS400 查询中获取一个列表,从 SQL Server 查询中获取另一个列表。我需要将这两个列表合并为一个列表。第一个列表是我们库存中的所有资产,如下所示:

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

第二个列表更详细,看起来像这样,两个列表都有一个共同的字段,卡车编号:

[
   {
        "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
        }
    }
]

我需要更新任何现有值,例如经度,同时添加第一个查询中没有的值。

我尝试了一些合并示例,但根本没有工作,或者其他人只是将第一个列表附加到第二个列表。


可能的解决方案:

有人看到这个问题吗?

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());

}

【问题讨论】:

  • 一个简单的方法是首先将两个列表映射到使用truckNumber 作为键和项目本身作为值的映射。然后,您可以遍历键集并从两个映射中获取相同的项目,将它们连接到您想要的任何方式中。
  • 如何创建 Java 对象的合并列表,然后转换回 JSON(假设您需要 JSON 中的合并列表)?
  • 地图看起来很有希望,但它必须与 JRE 1.7 兼容,所以没有 lamda 表达式。
  • 更改 if 条件为 if (!map.containsKey(key)) { map.put(key, t);无论如何 TruckNumber 在两个对象中都是相同的。为什么要重新设置?

标签: java json


【解决方案1】:

如果您使用Jackson(最流行的 JSON 库之一),您可以通过以下方式简单地实现:

代码片段

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));

控制台输出

[ 
  { 
    "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
    }
  }
]

【讨论】:

    【解决方案2】:

    试试下面的例子。我相信这可以满足您合并两个列表、更新任何现有值并最终添加任何不在第一个查询中的值的要求。

    另外,我考虑到您使用的是 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);
        }
    }
    

    输出:

    {
      "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
      }
    }
    

    出于性能的目的。您可以考虑使用 LinkedHashMap 与 HashMap,如上例所示。使用 LinkedHashMap 时迭代效率更高。下面的示例使用这种方法。

    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);
        }
    }
    

    两个示例代码都将产生您想要的结果,如上述输出所示。

    【讨论】:

    • @ConnieDeCinko - 我上面的实现是否满足您的要求?
    • 感觉你的解决方案比它需要的更复杂。它可能有效,但第一个解决方案也有效。我没有看到好处。
    • 我试图根据您的 cmets 为您提供答案;但是,如果您提到的第一个解决方案是您原始帖子中的解决方案合并了这两个列表,那么我会同意。祝你好运。
    • 谢谢。只是想了解为什么一种解决方案比另一种更好。直到现在才知道 LinkedHashMap。
    猜你喜欢
    • 2020-04-24
    • 2012-12-05
    • 1970-01-01
    • 1970-01-01
    • 2019-05-06
    • 1970-01-01
    • 1970-01-01
    • 2023-02-06
    • 2019-11-11
    相关资源
    最近更新 更多