如何通过比较Java中给定对象中的字段值来合并两个对象列表

如何通过比较Java中给定对象中的字段值来合并两个对象列表,java,arraylist,merge,Java,Arraylist,Merge,我有两个对象列表,我想把它们合并成一个。对象有两个字段,“名称”和“值”。对于列表2中的给定obj2,如果我们在列表1中找到obj1的“名称”字段匹配项(列表1中的obj1和列表2中的obj2),则我们使用obj2的“值”覆盖obj1。如果没有找到匹配项,则将obj2添加到列表1中。最终输出将更新为列表1 有什么快速的方法可以做到这一点吗?我所能想到的就是使用两个for循环来比较两个列表中的所有对象 class NameValueObj{ String name; String value; }

我有两个对象列表,我想把它们合并成一个。对象有两个字段,“名称”和“值”。对于列表2中的给定obj2,如果我们在列表1中找到obj1的“名称”字段匹配项(列表1中的obj1和列表2中的obj2),则我们使用obj2的“值”覆盖obj1。如果没有找到匹配项,则将obj2添加到列表1中。最终输出将更新为列表1

有什么快速的方法可以做到这一点吗?我所能想到的就是使用两个for循环来比较两个列表中的所有对象

class NameValueObj{
String name;
String value;
}

List<NameValueObj> merge(List<NameValueObj> list1, List<NameValueObj> list2){
// I want to merge two list here
}
类名称值obj{
字符串名;
字符串值;
}
列表合并(列表1、列表2){
//我想在这里合并两个列表
}
NameValueObj是一个给定的,所以我可以;不要修改对象源

这是我的方法

private List<Header> mergeHeaders(List<Header> defHeaders, List<Header> ovrdHeaders) {
        List<Header> lFinal = defHeaders;
        boolean foundMatch = false;
        for (Header ovrdHeader : ovrdHeaders) {
            foundMatch = false;
            for (Header defHeader : defHeaders) {
                if (defHeader.getName().equalsIgnoreCase(ovrdHeader.getName())) {
                    defHeader.setValue(ovrdHeader.getValue());
                    foundMatch = true;
                    break;
                }
            }
            if(!foundMatch) {
                lFinal.add(ovrdHeader);
            }

        }

        return lFinal;
    }
private List mergeHeaders(List defHeaders,List ovrdHeaders){
List lFinal=defHeaders;
布尔foundMatch=false;
for(标头ovrdHeader:ovrdHeaders){
foundMatch=false;
对于(标题defHeader:defHeaders){
if(defHeader.getName().equalsIgnoreCase(ovrdHeader.getName())){
setValue(ovrdHeader.getValue());
foundMatch=true;
打破
}
}
如果(!foundMatch){
l最终添加(ovrdHeader);
}
}
返回lFinal;
}

标头具有名称和值字段。标题在给定的列表中具有唯一的名称。

因此,如果您看到主要的效率开销,您的方法是搜索另一个列表中的特定元素。因此,您应该问,如何有效地在另一个列表中搜索对象

  • 数组(如果您知道索引)
  • HashMap(如果您知道密钥)
HashMap看起来是实现问题的简单方法。所以,您可以做的是遍历第一个列表,在映射中添加name作为key,value作为value。第二个列表也是如此

接下来,遍历第一个映射的键集,并在第二个列表中搜索相应的名称键。如果找到,在第一个列表中添加为值

这里的主要缺点是使用额外的数据结构。

您的算法是
O(n*n)
(二次型)

您可以在
O(n)
(线性)中使用临时
LinkedHashMap

private List<Header> mergeHeaders(final List<Header> defHeaders, final List<Header> ovrdHeaders) {
    final Map<String, Header> headersMap = new LinkedHashMap<String, Header>();

    for (final Header defHeader : defHeaders) {
        headersMap.put(defHeader.getName().toLowerCase(), defHeader);
    }

    for (final Header ovrdHeader : ovrdHeaders) {
        headersMap.put(ovrdHeader.getName().toLowerCase(), ovrdHeader);
    }

    return new ArrayList<Header>(headersMap.values());
}
  • 此实现假设头名称在两个列表中都是唯一的(不区分大小写),而您的列表中没有这样的假设
    如果标题名称不唯一,此实现将保留列表1或列表2中的最后一个标题


    • 我不得不解决一个类似的问题。在我的例子中,当哈希映射已经有或没有一个项时,我必须创建自定义决策规则。以下是我的最终解决方案:

      辅助类:

      公共接口合并规则{
      T olderListContains(T olderObj,T newObj);
      T olderListNotContains(T newObj);
      }
      公共抽象类HashAbstract{
      公共字符串getKey(){
      返回null;
      }
      }
      
      我的最终合并方法:

      公共静态列表合并(最终列表旧列表,
      最终名单新名单,
      合并规则(合并规则){
      final Map listMap=新建LinkedHashMap();
      用于(最后一个T olderObj:olderList){
      put(((HashAbstract)olderObj.getKey(),olderObj);
      }
      对于(最终T newObj:newList){
      字符串newObjKey=((HashAbstract)newObj.getKey();
      T返回obj;
      if(listMap.containsKey(newObjKey)){
      returnObj=mergeRules.olderListContains(listMap.get(newObjKey),newObj);
      }否则{
      returnObj=mergeRules.olderListNotContains(newObj);
      }
      put(newObjKey,returnObj);
      }
      返回新的ArrayList(listMap.values());
      }
      
      例如:

      class NameValueObj扩展了HashAbstract{
      公共字符串名称;
      公共字符串值;
      @凌驾
      公共字符串getKey(){
      返回name.trim().toUpperCase();
      }
      }
      NameValueObj obj1=新的NameValueObj();
      obj1.name=“测试”;
      obj1.value=“1234”;
      NameValueObj obj2=新的NameValueObj();
      obj2.name=“testSomething”;
      obj2.value=“4321”;
      NameValueObj obj3=新的NameValueObj();//将更新的obj
      obj3.name=“测试”;
      obj3.value=“1212”;
      NameValueObj obj4=新的NameValueObj();//新对象
      obj4.name=“testObj”;
      obj4.value=“1313”;
      List list1=新的ArrayList();
      列表1.添加(obj1);
      列表2.add(obj2);
      List list2=新的ArrayList();
      清单2.添加(obj3);
      清单2.添加(obj4);
      List mergedList=merge(列表1、列表2、,
      新的Compare.MergeRules(){
      @凌驾
      public NameValueObj olderListContains(NameValueObj olderObj,NameValueObj newObj){
      return newObj;//如果obj已经存在,则返回新的
      }
      @凌驾
      public NameValueObj olderListNotContains(NameValueObj newObj){
      return newObj;//如果不存在,则返回新的obj
      }
      });
      
      示例的
      mergedList

      name: test - value: 1212
      name: testSomething - value: 4321
      name: testObj - value: 1313
      

      谢谢你的解释。此算法速度快得多,但如果第二个列表中的项与第一个列表中的项具有相同的名称但值不同,则它无法解决“匹配场景”。它不会用此新项覆盖第一个列表。
      name: test - value: 1212
      name: testSomething - value: 4321
      name: testObj - value: 1313