-7

Suppose I have two list which i want to get merged into one

Merge Condition : compare with id

Case 1 : 
List 1 = [{id=1,name=null},{id=2,name=null},{id=3,name=c}]
List 2 = [{id=1,name=a},{id=2,name=b}]

After the merge, it should be [{id=1,name=a},{id=2,name=b},{id=3,name=c}]

Case 1 : 
List 1 = [{id=1,name=null}]
List 2 = [{id=1,name=a},{id=2,name=b}]

After the merge, it should be [{id=1,name=a},{id=2,name=b}]

My code:

 for (Object ObjofList1: list1) {
             List<DummyObject> do = new ArrayLIst();
            SomeObject sm = list2.stream()
                    .filter(list2object -> list2object.getId().equals(ObjofList1.getId()))
                    .findAny()
                    .orElse(ObjofList1);
                          do.add(dealerSalesTempObject);
          
        }

It is working fine if list2 has more elements in it, but if list1 has more element then we won't be able to merge because of less iteration.

My question is i don't want to see which one is shorter or longer but at last all objects should be in one list..

kole
  • 5
  • 5
  • Is it relevant whether list 1 is merged into list 2 or could it be the other way round, i.e. could you make the longer of the 2 list 2 and the shorter list 1? Do you want the merge to happen in-place, i.e. make changes to one list, or would you want a "merged" copy of the lists? – Thomas Sep 21 '20 at 09:02
  • My question is i don't want to see which one is shorter or longer but at last all objects should be in one list.. – kole Sep 21 '20 at 09:04
  • Note that your code wouldn't even compile, i.e. `do` is a reserved keyword and `dealerSalesTempObject` isn't defined - please post a [mcve]. – Thomas Sep 21 '20 at 09:04
  • Does this answer your question? [How do I join two lists in Java?](https://stackoverflow.com/questions/189559/how-do-i-join-two-lists-in-java) – flaxel Sep 21 '20 at 09:04
  • changed that @Thomas – kole Sep 21 '20 at 09:05
  • "i don't want to see which one is shorter or longer" - in that case just rearrange the lists so that the longer one is list 2 and you should be done. – Thomas Sep 21 '20 at 09:05
  • yes @Thomas that is the problem i want it in one short without checking the length – kole Sep 21 '20 at 09:07
  • 1
    see also this related question: https://stackoverflow.com/questions/16520046/how-to-merge-two-arraylists-without-duplicates – Hulk Sep 21 '20 at 09:21
  • In your case, if there is a conflict between list1 and list2, two elements with the same id, you always should consider list2 element? or there is no difference? – Ismail Sep 21 '20 at 10:00
  • i will consider that list which have some data in it after comparing with id – kole Sep 21 '20 at 10:04
  • @kole I'm not sure about why you don't want to check the length and rearrange by length since it would just be 1 or a few lines. Sometimes shorter code is not better code since it's harder to understand and write (see your case as an example). Also it is not clear what "merging" does mean as you can see by all the questions and assumptions in the answers. Additionally it's not clear if order needs to be preserved and whether or not you want a fresh list containing the merge result or do it in-place. – Thomas Sep 21 '20 at 10:07
  • i have just update the case 1 and case 2 example @Thomas can you look into it,, you will get what i am asking. – kole Sep 21 '20 at 10:10
  • One thing you _could_ do: put the elements of list 1 into a (linked hash) map with id being the key. (1 simple loop or using a stream) Then iterate over list 2 and get the map elements by id. If you found one do your merge, if not just put the element into the map. (thats 1 other simple loop). – Thomas Sep 21 '20 at 10:10
  • Yes, we can do that also. but just finding a way in stream. – kole Sep 21 '20 at 10:12

3 Answers3

4

Introducing Stream to such problem just makes things more complicated for no real reason. Based on your example you just want to create a Set containing elements from both Lists. Something like this would be the easiest way to achieve it:

Set<Object> resultSet = new HashSet<>(list1);
result.addAll(list2);
List<Object> resultList = new ArrayList<>(result); // optionally if u want a List

This solution assumes that your class implements equals() and hashcode() methods.

Amongalen
  • 3,101
  • 14
  • 20
2

You can merge these two lists using streams, and then use distinct, in order to remove duplicate elements, and finally reconvert it to a list:

Stream.concat(list1.stream(), list2.stream()).distinct().collect(Collectors.toList());

NOTE: you need to implement equals and hashcode in your DummyObject, it's required to remove the duplicated elements when generating the Set.

HashCode and Equals for your case (Considering the infos in the comments):

@Override
public boolean equals(Object o) {
    if (this == o) return true;
    if (o == null || getClass() != o.getClass()) return false;

    StockProcessData that = (StockProcessData) o;

    if (id != null ? !id.equals(that.id) : that.id != null) return false;
    if (unContractedStock != null ? !unContractedStock.equals(that.unContractedStock) : that.unContractedStock != null)
        return false;
    return contractedStock != null ? contractedStock.equals(that.contractedStock) : that.contractedStock == null;
}

@Override
public int hashCode() {
    int result = id != null ? id.hashCode() : 0;
    result = 31 * result + (unContractedStock != null ? unContractedStock.hashCode() : 0);
    result = 31 * result + (contractedStock != null ? contractedStock.hashCode() : 0);
    return result;
}
Ismail
  • 2,322
  • 1
  • 12
  • 26
  • there is no comparison with id – kole Sep 21 '20 at 09:05
  • You're right, I will edit the answer. – Ismail Sep 21 '20 at 09:05
  • @kole It will work if you add the hashcode and equals implementation in the DummyObject class, you can see the edits, I have also edited the streams. – Ismail Sep 21 '20 at 09:13
  • @Lino I forget to add the second call of stream, I have edited the answer, Sorry – Ismail Sep 21 '20 at 09:16
  • @Lino Thank you, It is better, I have edited the answer. – Ismail Sep 21 '20 at 09:19
  • one more thing i dont have any int type in my class...id is in String format then how to overrise hash in it – – kole Sep 21 '20 at 09:32
  • @kole There is no problem what is the type of your fields, you can generate an accurate hash and equals, you can generate the hashCode and equals automatically using your IDE. – Ismail Sep 21 '20 at 09:34
  • it is giving nullpointer exception – kole Sep 21 '20 at 09:39
  • `ask :SeerDataSalesWeightProcessor.main() FAILED [StockProcessData(id=23232, unContractedStock=34, contractedStock=null), StockProcessData(id=30000, unContractedStock=null, contractedStock=null)] Exception in thread "main" java.lang.NullPointerException` – kole Sep 21 '20 at 09:39
  • I think the problem is not related to the code above, I have tested it before posting the answer, maybe the generated hashCode or equals has some issues. I have edited the answer with hashCode and equals code for you. – Ismail Sep 21 '20 at 09:46
  • one question @Ismail By this we can achive that but we are not pasting one value to the object... for example merging means if object id = 1, name="null" from list 1 and object id= 1, name="a" from list 2 then after mergring the final output should be id=1 name= a in the new list – kole Sep 21 '20 at 09:48
  • 1
    @kole ahh, I see, I think you should specify this requirement in your question. Things will be different from there. – Ismail Sep 21 '20 at 09:51
2

You have updated your question and mentioned the use case of merging objects with the same id into a single object. The way I can think of would be something like this:

List<DummyObject> list3 = new ArrayList<>(
    Stream
        .concat(list1.stream(), list2.stream())
        .collect(Collectors.toMap(
            DummyObject::getId, 
            Function.identity(), 
            (a, b) -> {
                 // here you can merge a and b
            }
         ))
         .values()
    );

Old answer

No need for Streams, a simple SortedSet is enough:

SortedSet<DummyObject> result = new TreeSet<>(Comparator.comparing(DummyObject::getId));
result.addAll(list1);
result.addAll(list2);

The SortedSet can be used when you don't want to override the hashCode() and equals() methods. Additionally the result is sorted by id.

If you need a List afterwards you can convert it easily back:

List<DummyObject> list3 = new ArrayList<>(result);

But using a Set may be more declarative, as it clearly indicates that no duplicates are available.

Lino
  • 19,604
  • 6
  • 47
  • 65
  • Here we are comparing one obejct..but two list is there... i am not sure.. how to compare with list. – kole Sep 21 '20 at 09:11
  • @kole I don't quite understand what you mean? What do you mean with: *comparing one object but two list is there*, where are these lists? which object is compared? – Lino Sep 21 '20 at 09:12
  • 1
    @kole the Set uses the given comparator whenever elements are added, to determine the ordering and to enforce uniqueness. – Hulk Sep 21 '20 at 09:14
  • @Lino List1 List2 ::: comparing one object at a time from list_1 or list_2 and saving it in List3.. but the concern is we dont know which one have more element in it. and we are iterating on random list...at last list1 and list 2 will be merged on condition – kole Sep 21 '20 at 09:18
  • @kole My solution **does not care**. It works with any amount of elements. Have you tried it out? – Lino Sep 21 '20 at 09:19
  • ok so what i am saying as per your soulution object should be passed but from which list? `SortedSet result = new TreeSet<>(Comparator.comparing(DummyObject::getId));` – kole Sep 21 '20 at 09:23
  • 1
    @kole that constructor accepts a `Comparator` used to find out the *uniqueness* of a `DummyObject`. We first add all objects of `list1` by using `result.addAll(list1)` and the other call `result.addAll(list2)` adds all the objects of `list2` **BUT**, will check that an object with the same id does not already exists. Meaning the resulting `result` contains all unique objects. If you still don't understand, then I suggest you to look at the javadoc of `Set`, `SortedSet` and `TreeSet`, or generally the difference between `List` and `Set` – Lino Sep 21 '20 at 09:25
  • but what if i want to save also those things which is not present at all at list 1 but present in list2.. will that work? – kole Sep 21 '20 at 09:27
  • @kole yes it will, for reference have a look at [`Set#addAll(Collection)`](https://docs.oracle.com/javase/7/docs/api/java/util/Set.html#addAll(java.util.Collection)). *Adds all of the elements in the specified collection to this set if they're not already present* – Lino Sep 21 '20 at 09:30
  • nullpointer exception : ask :`SeerDataSalesWeightProcessor.main() FAILED [StockProcessData(id=23232, unContractedStock=34, contractedStock=null), StockProcessData(id=30000, unContractedStock=null, contractedStock=null)] Exception in thread "main" java.lang.NullPointerExceptio` @Lino – kole Sep 21 '20 at 09:40
  • @kole https://stackoverflow.com/questions/218384/what-is-a-nullpointerexception-and-how-do-i-fix-it – Lino Sep 21 '20 at 09:43
  • one question @Lino By this we can achive that but we are not pasting one value to the object... for example merging means if object id = 1, name="null" from list 1 and object id= 1, name="a" from list 2 then after mergring the final output should be id=1 name= a in the new list – kole Sep 21 '20 at 09:46
  • @kole Maybe with streams: `List list3 = new ArrayList<>(Stream.concat(list1.stream(), list2.stream()).collect(Collectors.toMap(DummyObject::getId, Function.identity(), (a, b) -> {/*your merge function*/})).values());` where you define a lambda to merge two objects (`a`, `b`) when they have the same id – Lino Sep 21 '20 at 09:53
  • @Lino Did the code as commented above... seems like promising to me – kole Sep 21 '20 at 10:10
  • Can u put your comment in ans so that it can be ticked out – kole Sep 21 '20 at 10:15