简体   繁体   中英

How to merge two lists of objects by comparing field value in the given objects in Java

I have two list of objects and I want to merge them into one. the objects have two fields, "name" and "value". For a given obj2 in list2 , if we find a match of "name" field of obj1 in list1 (obj1 from list1 and obj2 from list2), then we use the "value" of the obj2 to overwrite obj1. if there is no match found, then we add obj2 to list1. The final output will be updated list1.

Is there any fast way to do this? All I can think of is to use two for loops to compare all the objects in two lists

class NameValueObj{
String name;
String value;
}

List<NameValueObj> merge(List<NameValueObj> list1, List<NameValueObj> list2){
// I want to merge two list here
}

NameValueObj is a given so I can;t modify the object source.

Here is my way of doing it.

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

Header has name and value field. Headers has unique names in a given list.

Your algorithm is O(n*n) (quadratic).

You can do it in O(n) (linear) using a temporary 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());
}

Note that the behavior is NOT exactly the same as the behavior of your implementation. The differences are:

  • This implementation returns a new list instance instead of modifying the first list. IMO, it's a benefit, but it may depend. If needed, you can modify the first list as follows (though I'd not recommend that):

     defHeaders.clear(); defHeaders.addAll(headersMap.values()); return defHeaders; 
  • This implementation assumes that header names are already unique (case INsensitively) in both lists, while your one doesn't make this assumption.
    If header names are not unique, this implementation would preserve the last header from list 1 or list 2.

So if you see the major efficiency overhead your way is searching for a particular element in another list. So you should ask how can you efficiently search for the object in another list?

  • Array(if you know the index)
  • HashMap(if you kow the key)

HashMap looks like an easy way to implement your problem. So what you can do is iterate through your first list and add name as key and value as value in the map. Similarly for the second list.

Next iterate through the keyset of 1st map and search for corresponding name key in 2nd list. If found add as value in 1st list.

The major drawback here is using extra data structures.

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