Efficiently compare 2 lists to replace and order












4















I have 2 list containing some Objects (Fruit class). I am using a 3rd list to add these elements based on following 2 criteria.



I want every object in the 1st list added to 3rd list. But if I have a matching object in the 2nd list (matching based on id and isChecked), I want to add the object from the 2nd list to the 3rd list and ignore the one in 1st list.



If I did the switch mentioned on point one, I want to move that object up to the first element of the 3rd list.



I have it working with following code. But I find it very inefficient. Is there a better way around it?



Bear in mind I have no control over the second list, but the first list is coming from a Rest endpoint and I am currently capturing it as a list. Unsure if I should have opted for a Map. Please advice.



Example:



In the following example, expected list output is [f2, f5, f1, f3, f4] (based on name).



It is cos I have all the elements from the first list. f2 and f5 went in front of the order as they came from second list (they matched elements in first list and had isChecked set to true).



import lombok.*;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class App {
public static void main(String args) {

Fruit fruit1 = new Fruit("1", "f1", false);
Fruit fruit2 = new Fruit("2", "f2", false);
Fruit fruit3 = new Fruit("3", "f3", false);
Fruit fruit4 = new Fruit("4", "f4", false);
Fruit fruit5 = new Fruit("5", "f5", false);

List<Fruit> firstList = Arrays.asList(fruit1, fruit2, fruit3, fruit4, fruit5);

Fruit fruit6 = new Fruit("2", "f2", true);
Fruit fruit7 = new Fruit("7", "f7", false);
Fruit fruit8 = new Fruit("5", "f5", true);
Fruit fruit9 = new Fruit("9", "f9", false);
Fruit fruit10 = new Fruit("10", "f10", false);

List<Fruit> secondList = Arrays.asList(fruit6, fruit7, fruit8, fruit9, fruit10);

List<Fruit> finalList = new ArrayList<>();

// expected list = [f2, f5, f1, f3, f4]

// this loop is checking and adding objects to finalList.
// must match the first list and isChecked.
// in this case, only f6 and f8 matches the first list (id match) and is also 'checked'.
for (Fruit first : firstList){
for (Fruit second : secondList){
if(first.getId().equals(second.getId()) && second.isChecked()){
finalList.add(second);
break;
}
}
}

// not done yet. Still need to loop and add back the elements from the first list
// which were not added in the above loop
boolean addedFirst = false;
outer:
for(Fruit first : firstList){
for(Fruit finalFruit : finalList){
if(first.getId().equals(finalFruit.getId())){
continue outer;
}
}
finalList.add(first);
}

for(Fruit fruit : finalList){
System.out.println(fruit);
}
}
}

@Getter
@Setter
@ToString
class Fruit{
private String id;
private String name;
private boolean isChecked;

Fruit(String id, String name, boolean isChecked) {
this.id = id;
this.name = name;
this.isChecked = isChecked;
}
}









share|improve this question























  • Use comparators for Object comparisons in Collection framework

    – praba buddy
    yesterday











  • This looks like code review to me, probably better to post at codereview.stackexchange.com

    – Joakim Danielson
    yesterday
















4















I have 2 list containing some Objects (Fruit class). I am using a 3rd list to add these elements based on following 2 criteria.



I want every object in the 1st list added to 3rd list. But if I have a matching object in the 2nd list (matching based on id and isChecked), I want to add the object from the 2nd list to the 3rd list and ignore the one in 1st list.



If I did the switch mentioned on point one, I want to move that object up to the first element of the 3rd list.



I have it working with following code. But I find it very inefficient. Is there a better way around it?



Bear in mind I have no control over the second list, but the first list is coming from a Rest endpoint and I am currently capturing it as a list. Unsure if I should have opted for a Map. Please advice.



Example:



In the following example, expected list output is [f2, f5, f1, f3, f4] (based on name).



It is cos I have all the elements from the first list. f2 and f5 went in front of the order as they came from second list (they matched elements in first list and had isChecked set to true).



import lombok.*;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class App {
public static void main(String args) {

Fruit fruit1 = new Fruit("1", "f1", false);
Fruit fruit2 = new Fruit("2", "f2", false);
Fruit fruit3 = new Fruit("3", "f3", false);
Fruit fruit4 = new Fruit("4", "f4", false);
Fruit fruit5 = new Fruit("5", "f5", false);

List<Fruit> firstList = Arrays.asList(fruit1, fruit2, fruit3, fruit4, fruit5);

Fruit fruit6 = new Fruit("2", "f2", true);
Fruit fruit7 = new Fruit("7", "f7", false);
Fruit fruit8 = new Fruit("5", "f5", true);
Fruit fruit9 = new Fruit("9", "f9", false);
Fruit fruit10 = new Fruit("10", "f10", false);

List<Fruit> secondList = Arrays.asList(fruit6, fruit7, fruit8, fruit9, fruit10);

List<Fruit> finalList = new ArrayList<>();

// expected list = [f2, f5, f1, f3, f4]

// this loop is checking and adding objects to finalList.
// must match the first list and isChecked.
// in this case, only f6 and f8 matches the first list (id match) and is also 'checked'.
for (Fruit first : firstList){
for (Fruit second : secondList){
if(first.getId().equals(second.getId()) && second.isChecked()){
finalList.add(second);
break;
}
}
}

// not done yet. Still need to loop and add back the elements from the first list
// which were not added in the above loop
boolean addedFirst = false;
outer:
for(Fruit first : firstList){
for(Fruit finalFruit : finalList){
if(first.getId().equals(finalFruit.getId())){
continue outer;
}
}
finalList.add(first);
}

for(Fruit fruit : finalList){
System.out.println(fruit);
}
}
}

@Getter
@Setter
@ToString
class Fruit{
private String id;
private String name;
private boolean isChecked;

Fruit(String id, String name, boolean isChecked) {
this.id = id;
this.name = name;
this.isChecked = isChecked;
}
}









share|improve this question























  • Use comparators for Object comparisons in Collection framework

    – praba buddy
    yesterday











  • This looks like code review to me, probably better to post at codereview.stackexchange.com

    – Joakim Danielson
    yesterday














4












4








4


1






I have 2 list containing some Objects (Fruit class). I am using a 3rd list to add these elements based on following 2 criteria.



I want every object in the 1st list added to 3rd list. But if I have a matching object in the 2nd list (matching based on id and isChecked), I want to add the object from the 2nd list to the 3rd list and ignore the one in 1st list.



If I did the switch mentioned on point one, I want to move that object up to the first element of the 3rd list.



I have it working with following code. But I find it very inefficient. Is there a better way around it?



Bear in mind I have no control over the second list, but the first list is coming from a Rest endpoint and I am currently capturing it as a list. Unsure if I should have opted for a Map. Please advice.



Example:



In the following example, expected list output is [f2, f5, f1, f3, f4] (based on name).



It is cos I have all the elements from the first list. f2 and f5 went in front of the order as they came from second list (they matched elements in first list and had isChecked set to true).



import lombok.*;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class App {
public static void main(String args) {

Fruit fruit1 = new Fruit("1", "f1", false);
Fruit fruit2 = new Fruit("2", "f2", false);
Fruit fruit3 = new Fruit("3", "f3", false);
Fruit fruit4 = new Fruit("4", "f4", false);
Fruit fruit5 = new Fruit("5", "f5", false);

List<Fruit> firstList = Arrays.asList(fruit1, fruit2, fruit3, fruit4, fruit5);

Fruit fruit6 = new Fruit("2", "f2", true);
Fruit fruit7 = new Fruit("7", "f7", false);
Fruit fruit8 = new Fruit("5", "f5", true);
Fruit fruit9 = new Fruit("9", "f9", false);
Fruit fruit10 = new Fruit("10", "f10", false);

List<Fruit> secondList = Arrays.asList(fruit6, fruit7, fruit8, fruit9, fruit10);

List<Fruit> finalList = new ArrayList<>();

// expected list = [f2, f5, f1, f3, f4]

// this loop is checking and adding objects to finalList.
// must match the first list and isChecked.
// in this case, only f6 and f8 matches the first list (id match) and is also 'checked'.
for (Fruit first : firstList){
for (Fruit second : secondList){
if(first.getId().equals(second.getId()) && second.isChecked()){
finalList.add(second);
break;
}
}
}

// not done yet. Still need to loop and add back the elements from the first list
// which were not added in the above loop
boolean addedFirst = false;
outer:
for(Fruit first : firstList){
for(Fruit finalFruit : finalList){
if(first.getId().equals(finalFruit.getId())){
continue outer;
}
}
finalList.add(first);
}

for(Fruit fruit : finalList){
System.out.println(fruit);
}
}
}

@Getter
@Setter
@ToString
class Fruit{
private String id;
private String name;
private boolean isChecked;

Fruit(String id, String name, boolean isChecked) {
this.id = id;
this.name = name;
this.isChecked = isChecked;
}
}









share|improve this question














I have 2 list containing some Objects (Fruit class). I am using a 3rd list to add these elements based on following 2 criteria.



I want every object in the 1st list added to 3rd list. But if I have a matching object in the 2nd list (matching based on id and isChecked), I want to add the object from the 2nd list to the 3rd list and ignore the one in 1st list.



If I did the switch mentioned on point one, I want to move that object up to the first element of the 3rd list.



I have it working with following code. But I find it very inefficient. Is there a better way around it?



Bear in mind I have no control over the second list, but the first list is coming from a Rest endpoint and I am currently capturing it as a list. Unsure if I should have opted for a Map. Please advice.



Example:



In the following example, expected list output is [f2, f5, f1, f3, f4] (based on name).



It is cos I have all the elements from the first list. f2 and f5 went in front of the order as they came from second list (they matched elements in first list and had isChecked set to true).



import lombok.*;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class App {
public static void main(String args) {

Fruit fruit1 = new Fruit("1", "f1", false);
Fruit fruit2 = new Fruit("2", "f2", false);
Fruit fruit3 = new Fruit("3", "f3", false);
Fruit fruit4 = new Fruit("4", "f4", false);
Fruit fruit5 = new Fruit("5", "f5", false);

List<Fruit> firstList = Arrays.asList(fruit1, fruit2, fruit3, fruit4, fruit5);

Fruit fruit6 = new Fruit("2", "f2", true);
Fruit fruit7 = new Fruit("7", "f7", false);
Fruit fruit8 = new Fruit("5", "f5", true);
Fruit fruit9 = new Fruit("9", "f9", false);
Fruit fruit10 = new Fruit("10", "f10", false);

List<Fruit> secondList = Arrays.asList(fruit6, fruit7, fruit8, fruit9, fruit10);

List<Fruit> finalList = new ArrayList<>();

// expected list = [f2, f5, f1, f3, f4]

// this loop is checking and adding objects to finalList.
// must match the first list and isChecked.
// in this case, only f6 and f8 matches the first list (id match) and is also 'checked'.
for (Fruit first : firstList){
for (Fruit second : secondList){
if(first.getId().equals(second.getId()) && second.isChecked()){
finalList.add(second);
break;
}
}
}

// not done yet. Still need to loop and add back the elements from the first list
// which were not added in the above loop
boolean addedFirst = false;
outer:
for(Fruit first : firstList){
for(Fruit finalFruit : finalList){
if(first.getId().equals(finalFruit.getId())){
continue outer;
}
}
finalList.add(first);
}

for(Fruit fruit : finalList){
System.out.println(fruit);
}
}
}

@Getter
@Setter
@ToString
class Fruit{
private String id;
private String name;
private boolean isChecked;

Fruit(String id, String name, boolean isChecked) {
this.id = id;
this.name = name;
this.isChecked = isChecked;
}
}






java






share|improve this question













share|improve this question











share|improve this question




share|improve this question










asked yesterday









kangkang

28119




28119













  • Use comparators for Object comparisons in Collection framework

    – praba buddy
    yesterday











  • This looks like code review to me, probably better to post at codereview.stackexchange.com

    – Joakim Danielson
    yesterday



















  • Use comparators for Object comparisons in Collection framework

    – praba buddy
    yesterday











  • This looks like code review to me, probably better to post at codereview.stackexchange.com

    – Joakim Danielson
    yesterday

















Use comparators for Object comparisons in Collection framework

– praba buddy
yesterday





Use comparators for Object comparisons in Collection framework

– praba buddy
yesterday













This looks like code review to me, probably better to post at codereview.stackexchange.com

– Joakim Danielson
yesterday





This looks like code review to me, probably better to post at codereview.stackexchange.com

– Joakim Danielson
yesterday












4 Answers
4






active

oldest

votes


















3














My advice is to override Object#equals(java.lang.Object) for the Fruit class.



@Override
public boolean equals(Object obj) {
if (!(obj instanceof Fruit))
return false;
return id.equals(((Fruit)obj).getId());
}


. . .



for (Fruit fruit : firstList) {
if (secondList.contains(fruit)) {
int index = secondList.indexOf(fruit);
fruit = secondList.get(index);
}
finalList.add(fruit);
}




In order to mantain the desired sort order - 2nd list elements first, then the unmatching elements in the 2nd - one can do:



List<Fruit> finalList = new ArrayList<>(secondList);
finalList.retainAll(firstList);
for (Fruit fruit : firstList) {
if (!finalList.contains(fruit))
finalList.add(fruit);
}


The finalList order is now [f2, f5, f1, f3, f4].



This works again because of the equals method override.



See java.util.List.retainAll().



Each of these approaches use a linear O(n) computational time for every loop and search operation - like indexOf andretainAll.





Related to the topic, I think it's not really clear what you want to achieve:




f2 and f5 went in front of the order as they came from second list (they matched elements in first list and had isChecked set to true)




What should happen if isChecked in the first list were set to false? Do the elements in the second list come always first and isChecked order is retained so basically you want two different kind of sorting in the same resulting list?






share|improve this answer


























  • isChecked in first list will always be false. Only second list has possibility to have isChecked set to true. Thus elements in second list will be pushed first (as per the requirements where all objects from 1st list is added, an object from second list is used instead if it matches an object in first list and isChecked=true and also pushed up the order). I get your solution. Still pondering a way around to get 0(1) instead of O(n) which presumebly at this stage seems impossible.

    – kang
    yesterday



















1














I think you could use Map to build result list. It takes O(n) additional space and O(n) time to build third list.



public static List<Fruit> buildFinalList(List<Fruit> firstList, List<Fruit> secondList) {
Map<String, Fruit> map = secondList.stream().collect(Collectors.toMap(Fruit::getId, Function.identity()));

List<Fruit> finalList = firstList.stream()
.filter(fruit -> map.containsKey(fruit.getId()))
.map(fruit -> map.get(fruit.getId()))
.collect(Collectors.toList());
firstList.stream()
.filter(fruit -> !map.containsKey(fruit.getId()))
.forEach(finalList::add);

return finalList;
}




Output:



Fruit{id='2', name='f2', isChecked=true}
Fruit{id='5', name='f5', isChecked=true}
Fruit{id='1', name='f1', isChecked=false}
Fruit{id='3', name='f3', isChecked=false}
Fruit{id='4', name='f4', isChecked=false}





share|improve this answer


























  • This does the replacement fine, but I don't get the order where if I made a switch, it should move up the order. Meaning if I made a switch, it went up to index 0. If another switch, it went up to index 1 and so on.

    – kang
    yesterday













  • No problem. Use TreeMap or LinkedHashMap instead.

    – oleg.cherednik
    yesterday











  • Mistyped earlier comment. Not sure if you read it fully.

    – kang
    yesterday











  • Fixed. Not output matches with expectations.

    – oleg.cherednik
    yesterday



















0














You can try below




  1. Add all items from 1st List to 3rd List

  2. Compare 2nd & 3rd Lists and remove the common items or the condition (see compareTo method in Fruit Class)

  3. If Items are removed from 3rd List add the same item from 2nd to 3rd List


Please see the code below,



finalList.addAll(firstList);
for (Fruit secondfruit : secondList) {
boolean isRemoved = finalList.removeIf(firstfruit -> firstfruit.compareTo(secondfruit) == 0);
if(isRemoved) {
finalList.add(secondfruit);
}
}
for (Fruit fruit : finalList) {
System.out.println(fruit.getName());
}


Fruit class with Comparable,



class Fruit implements Comparable<Fruit> {
private String id;
private String name;
private boolean isChecked;

@Override
public int compareTo(Fruit o) {
if (o.isChecked && this.id.equalsIgnoreCase(o.id)) {
return 0;
}
else {
return 1;
}
}
}


Result is,
f1
f3
f4
f2
f5






share|improve this answer


























  • Hi, I get what you are doing. But I believe I would lose order in this way. if(isRemoved) {finalList.add(secondfruit);} This got added to the end of the list when it should have climbed up the order. Can't add to index 0 either since the item at that index may already have isChecked.

    – kang
    yesterday











  • Result should be f2, f5, f1, f3, f4

    – kang
    yesterday



















0














Assume the firstList length is n,the secondList length is m,your can cost O(nlogn) + O(mlogm) +O(n+m) to solve the problem. The algorithm like merge sort.



public static List<Fruit> merge(List<Fruit> list1, List<Fruit> list2) {
// sort list1 and list2
Comparator<Fruit> comparator = Comparator.comparingInt(o -> Integer.parseInt(o.getId()));
Collections.sort(list1, comparator);
Collections.sort(list2, comparator);

List<Fruit> finalList1 = new ArrayList<>();
List<Fruit> finalList2 = new ArrayList<>();
int length1 = list1.size();
int length2 = list2.size();
int index1 = 0;
int index2 = 0;

while (index1 < length1 && index2 < length2) {
Fruit fruit1 = list1.get(index1);
Fruit fruit2 = list2.get(index2);
if (fruit1.getId().equals(fruit2.getId()) && fruit2.isChecked()) {
finalList2.add(fruit2);
index2++;
index1++;
} else {
finalList1.add(fruit1);
index1++;
}
}

while (index1 < length1) {
finalList1.add(list1.get(index1));
index1++;
}

finalList2.addAll(finalList1);
return finalList2;
}





share|improve this answer























    Your Answer






    StackExchange.ifUsing("editor", function () {
    StackExchange.using("externalEditor", function () {
    StackExchange.using("snippets", function () {
    StackExchange.snippets.init();
    });
    });
    }, "code-snippets");

    StackExchange.ready(function() {
    var channelOptions = {
    tags: "".split(" "),
    id: "1"
    };
    initTagRenderer("".split(" "), "".split(" "), channelOptions);

    StackExchange.using("externalEditor", function() {
    // Have to fire editor after snippets, if snippets enabled
    if (StackExchange.settings.snippets.snippetsEnabled) {
    StackExchange.using("snippets", function() {
    createEditor();
    });
    }
    else {
    createEditor();
    }
    });

    function createEditor() {
    StackExchange.prepareEditor({
    heartbeatType: 'answer',
    autoActivateHeartbeat: false,
    convertImagesToLinks: true,
    noModals: true,
    showLowRepImageUploadWarning: true,
    reputationToPostImages: 10,
    bindNavPrevention: true,
    postfix: "",
    imageUploader: {
    brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
    contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
    allowUrls: true
    },
    onDemand: true,
    discardSelector: ".discard-answer"
    ,immediatelyShowMarkdownHelp:true
    });


    }
    });














    draft saved

    draft discarded


















    StackExchange.ready(
    function () {
    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f54251146%2fefficiently-compare-2-lists-to-replace-and-order%23new-answer', 'question_page');
    }
    );

    Post as a guest















    Required, but never shown

























    4 Answers
    4






    active

    oldest

    votes








    4 Answers
    4






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes









    3














    My advice is to override Object#equals(java.lang.Object) for the Fruit class.



    @Override
    public boolean equals(Object obj) {
    if (!(obj instanceof Fruit))
    return false;
    return id.equals(((Fruit)obj).getId());
    }


    . . .



    for (Fruit fruit : firstList) {
    if (secondList.contains(fruit)) {
    int index = secondList.indexOf(fruit);
    fruit = secondList.get(index);
    }
    finalList.add(fruit);
    }




    In order to mantain the desired sort order - 2nd list elements first, then the unmatching elements in the 2nd - one can do:



    List<Fruit> finalList = new ArrayList<>(secondList);
    finalList.retainAll(firstList);
    for (Fruit fruit : firstList) {
    if (!finalList.contains(fruit))
    finalList.add(fruit);
    }


    The finalList order is now [f2, f5, f1, f3, f4].



    This works again because of the equals method override.



    See java.util.List.retainAll().



    Each of these approaches use a linear O(n) computational time for every loop and search operation - like indexOf andretainAll.





    Related to the topic, I think it's not really clear what you want to achieve:




    f2 and f5 went in front of the order as they came from second list (they matched elements in first list and had isChecked set to true)




    What should happen if isChecked in the first list were set to false? Do the elements in the second list come always first and isChecked order is retained so basically you want two different kind of sorting in the same resulting list?






    share|improve this answer


























    • isChecked in first list will always be false. Only second list has possibility to have isChecked set to true. Thus elements in second list will be pushed first (as per the requirements where all objects from 1st list is added, an object from second list is used instead if it matches an object in first list and isChecked=true and also pushed up the order). I get your solution. Still pondering a way around to get 0(1) instead of O(n) which presumebly at this stage seems impossible.

      – kang
      yesterday
















    3














    My advice is to override Object#equals(java.lang.Object) for the Fruit class.



    @Override
    public boolean equals(Object obj) {
    if (!(obj instanceof Fruit))
    return false;
    return id.equals(((Fruit)obj).getId());
    }


    . . .



    for (Fruit fruit : firstList) {
    if (secondList.contains(fruit)) {
    int index = secondList.indexOf(fruit);
    fruit = secondList.get(index);
    }
    finalList.add(fruit);
    }




    In order to mantain the desired sort order - 2nd list elements first, then the unmatching elements in the 2nd - one can do:



    List<Fruit> finalList = new ArrayList<>(secondList);
    finalList.retainAll(firstList);
    for (Fruit fruit : firstList) {
    if (!finalList.contains(fruit))
    finalList.add(fruit);
    }


    The finalList order is now [f2, f5, f1, f3, f4].



    This works again because of the equals method override.



    See java.util.List.retainAll().



    Each of these approaches use a linear O(n) computational time for every loop and search operation - like indexOf andretainAll.





    Related to the topic, I think it's not really clear what you want to achieve:




    f2 and f5 went in front of the order as they came from second list (they matched elements in first list and had isChecked set to true)




    What should happen if isChecked in the first list were set to false? Do the elements in the second list come always first and isChecked order is retained so basically you want two different kind of sorting in the same resulting list?






    share|improve this answer


























    • isChecked in first list will always be false. Only second list has possibility to have isChecked set to true. Thus elements in second list will be pushed first (as per the requirements where all objects from 1st list is added, an object from second list is used instead if it matches an object in first list and isChecked=true and also pushed up the order). I get your solution. Still pondering a way around to get 0(1) instead of O(n) which presumebly at this stage seems impossible.

      – kang
      yesterday














    3












    3








    3







    My advice is to override Object#equals(java.lang.Object) for the Fruit class.



    @Override
    public boolean equals(Object obj) {
    if (!(obj instanceof Fruit))
    return false;
    return id.equals(((Fruit)obj).getId());
    }


    . . .



    for (Fruit fruit : firstList) {
    if (secondList.contains(fruit)) {
    int index = secondList.indexOf(fruit);
    fruit = secondList.get(index);
    }
    finalList.add(fruit);
    }




    In order to mantain the desired sort order - 2nd list elements first, then the unmatching elements in the 2nd - one can do:



    List<Fruit> finalList = new ArrayList<>(secondList);
    finalList.retainAll(firstList);
    for (Fruit fruit : firstList) {
    if (!finalList.contains(fruit))
    finalList.add(fruit);
    }


    The finalList order is now [f2, f5, f1, f3, f4].



    This works again because of the equals method override.



    See java.util.List.retainAll().



    Each of these approaches use a linear O(n) computational time for every loop and search operation - like indexOf andretainAll.





    Related to the topic, I think it's not really clear what you want to achieve:




    f2 and f5 went in front of the order as they came from second list (they matched elements in first list and had isChecked set to true)




    What should happen if isChecked in the first list were set to false? Do the elements in the second list come always first and isChecked order is retained so basically you want two different kind of sorting in the same resulting list?






    share|improve this answer















    My advice is to override Object#equals(java.lang.Object) for the Fruit class.



    @Override
    public boolean equals(Object obj) {
    if (!(obj instanceof Fruit))
    return false;
    return id.equals(((Fruit)obj).getId());
    }


    . . .



    for (Fruit fruit : firstList) {
    if (secondList.contains(fruit)) {
    int index = secondList.indexOf(fruit);
    fruit = secondList.get(index);
    }
    finalList.add(fruit);
    }




    In order to mantain the desired sort order - 2nd list elements first, then the unmatching elements in the 2nd - one can do:



    List<Fruit> finalList = new ArrayList<>(secondList);
    finalList.retainAll(firstList);
    for (Fruit fruit : firstList) {
    if (!finalList.contains(fruit))
    finalList.add(fruit);
    }


    The finalList order is now [f2, f5, f1, f3, f4].



    This works again because of the equals method override.



    See java.util.List.retainAll().



    Each of these approaches use a linear O(n) computational time for every loop and search operation - like indexOf andretainAll.





    Related to the topic, I think it's not really clear what you want to achieve:




    f2 and f5 went in front of the order as they came from second list (they matched elements in first list and had isChecked set to true)




    What should happen if isChecked in the first list were set to false? Do the elements in the second list come always first and isChecked order is retained so basically you want two different kind of sorting in the same resulting list?







    share|improve this answer














    share|improve this answer



    share|improve this answer








    edited yesterday

























    answered yesterday









    fantaghiroccofantaghirocco

    3,64452436




    3,64452436













    • isChecked in first list will always be false. Only second list has possibility to have isChecked set to true. Thus elements in second list will be pushed first (as per the requirements where all objects from 1st list is added, an object from second list is used instead if it matches an object in first list and isChecked=true and also pushed up the order). I get your solution. Still pondering a way around to get 0(1) instead of O(n) which presumebly at this stage seems impossible.

      – kang
      yesterday



















    • isChecked in first list will always be false. Only second list has possibility to have isChecked set to true. Thus elements in second list will be pushed first (as per the requirements where all objects from 1st list is added, an object from second list is used instead if it matches an object in first list and isChecked=true and also pushed up the order). I get your solution. Still pondering a way around to get 0(1) instead of O(n) which presumebly at this stage seems impossible.

      – kang
      yesterday

















    isChecked in first list will always be false. Only second list has possibility to have isChecked set to true. Thus elements in second list will be pushed first (as per the requirements where all objects from 1st list is added, an object from second list is used instead if it matches an object in first list and isChecked=true and also pushed up the order). I get your solution. Still pondering a way around to get 0(1) instead of O(n) which presumebly at this stage seems impossible.

    – kang
    yesterday





    isChecked in first list will always be false. Only second list has possibility to have isChecked set to true. Thus elements in second list will be pushed first (as per the requirements where all objects from 1st list is added, an object from second list is used instead if it matches an object in first list and isChecked=true and also pushed up the order). I get your solution. Still pondering a way around to get 0(1) instead of O(n) which presumebly at this stage seems impossible.

    – kang
    yesterday













    1














    I think you could use Map to build result list. It takes O(n) additional space and O(n) time to build third list.



    public static List<Fruit> buildFinalList(List<Fruit> firstList, List<Fruit> secondList) {
    Map<String, Fruit> map = secondList.stream().collect(Collectors.toMap(Fruit::getId, Function.identity()));

    List<Fruit> finalList = firstList.stream()
    .filter(fruit -> map.containsKey(fruit.getId()))
    .map(fruit -> map.get(fruit.getId()))
    .collect(Collectors.toList());
    firstList.stream()
    .filter(fruit -> !map.containsKey(fruit.getId()))
    .forEach(finalList::add);

    return finalList;
    }




    Output:



    Fruit{id='2', name='f2', isChecked=true}
    Fruit{id='5', name='f5', isChecked=true}
    Fruit{id='1', name='f1', isChecked=false}
    Fruit{id='3', name='f3', isChecked=false}
    Fruit{id='4', name='f4', isChecked=false}





    share|improve this answer


























    • This does the replacement fine, but I don't get the order where if I made a switch, it should move up the order. Meaning if I made a switch, it went up to index 0. If another switch, it went up to index 1 and so on.

      – kang
      yesterday













    • No problem. Use TreeMap or LinkedHashMap instead.

      – oleg.cherednik
      yesterday











    • Mistyped earlier comment. Not sure if you read it fully.

      – kang
      yesterday











    • Fixed. Not output matches with expectations.

      – oleg.cherednik
      yesterday
















    1














    I think you could use Map to build result list. It takes O(n) additional space and O(n) time to build third list.



    public static List<Fruit> buildFinalList(List<Fruit> firstList, List<Fruit> secondList) {
    Map<String, Fruit> map = secondList.stream().collect(Collectors.toMap(Fruit::getId, Function.identity()));

    List<Fruit> finalList = firstList.stream()
    .filter(fruit -> map.containsKey(fruit.getId()))
    .map(fruit -> map.get(fruit.getId()))
    .collect(Collectors.toList());
    firstList.stream()
    .filter(fruit -> !map.containsKey(fruit.getId()))
    .forEach(finalList::add);

    return finalList;
    }




    Output:



    Fruit{id='2', name='f2', isChecked=true}
    Fruit{id='5', name='f5', isChecked=true}
    Fruit{id='1', name='f1', isChecked=false}
    Fruit{id='3', name='f3', isChecked=false}
    Fruit{id='4', name='f4', isChecked=false}





    share|improve this answer


























    • This does the replacement fine, but I don't get the order where if I made a switch, it should move up the order. Meaning if I made a switch, it went up to index 0. If another switch, it went up to index 1 and so on.

      – kang
      yesterday













    • No problem. Use TreeMap or LinkedHashMap instead.

      – oleg.cherednik
      yesterday











    • Mistyped earlier comment. Not sure if you read it fully.

      – kang
      yesterday











    • Fixed. Not output matches with expectations.

      – oleg.cherednik
      yesterday














    1












    1








    1







    I think you could use Map to build result list. It takes O(n) additional space and O(n) time to build third list.



    public static List<Fruit> buildFinalList(List<Fruit> firstList, List<Fruit> secondList) {
    Map<String, Fruit> map = secondList.stream().collect(Collectors.toMap(Fruit::getId, Function.identity()));

    List<Fruit> finalList = firstList.stream()
    .filter(fruit -> map.containsKey(fruit.getId()))
    .map(fruit -> map.get(fruit.getId()))
    .collect(Collectors.toList());
    firstList.stream()
    .filter(fruit -> !map.containsKey(fruit.getId()))
    .forEach(finalList::add);

    return finalList;
    }




    Output:



    Fruit{id='2', name='f2', isChecked=true}
    Fruit{id='5', name='f5', isChecked=true}
    Fruit{id='1', name='f1', isChecked=false}
    Fruit{id='3', name='f3', isChecked=false}
    Fruit{id='4', name='f4', isChecked=false}





    share|improve this answer















    I think you could use Map to build result list. It takes O(n) additional space and O(n) time to build third list.



    public static List<Fruit> buildFinalList(List<Fruit> firstList, List<Fruit> secondList) {
    Map<String, Fruit> map = secondList.stream().collect(Collectors.toMap(Fruit::getId, Function.identity()));

    List<Fruit> finalList = firstList.stream()
    .filter(fruit -> map.containsKey(fruit.getId()))
    .map(fruit -> map.get(fruit.getId()))
    .collect(Collectors.toList());
    firstList.stream()
    .filter(fruit -> !map.containsKey(fruit.getId()))
    .forEach(finalList::add);

    return finalList;
    }




    Output:



    Fruit{id='2', name='f2', isChecked=true}
    Fruit{id='5', name='f5', isChecked=true}
    Fruit{id='1', name='f1', isChecked=false}
    Fruit{id='3', name='f3', isChecked=false}
    Fruit{id='4', name='f4', isChecked=false}






    share|improve this answer














    share|improve this answer



    share|improve this answer








    edited yesterday

























    answered yesterday









    oleg.cherednikoleg.cherednik

    6,11121118




    6,11121118













    • This does the replacement fine, but I don't get the order where if I made a switch, it should move up the order. Meaning if I made a switch, it went up to index 0. If another switch, it went up to index 1 and so on.

      – kang
      yesterday













    • No problem. Use TreeMap or LinkedHashMap instead.

      – oleg.cherednik
      yesterday











    • Mistyped earlier comment. Not sure if you read it fully.

      – kang
      yesterday











    • Fixed. Not output matches with expectations.

      – oleg.cherednik
      yesterday



















    • This does the replacement fine, but I don't get the order where if I made a switch, it should move up the order. Meaning if I made a switch, it went up to index 0. If another switch, it went up to index 1 and so on.

      – kang
      yesterday













    • No problem. Use TreeMap or LinkedHashMap instead.

      – oleg.cherednik
      yesterday











    • Mistyped earlier comment. Not sure if you read it fully.

      – kang
      yesterday











    • Fixed. Not output matches with expectations.

      – oleg.cherednik
      yesterday

















    This does the replacement fine, but I don't get the order where if I made a switch, it should move up the order. Meaning if I made a switch, it went up to index 0. If another switch, it went up to index 1 and so on.

    – kang
    yesterday







    This does the replacement fine, but I don't get the order where if I made a switch, it should move up the order. Meaning if I made a switch, it went up to index 0. If another switch, it went up to index 1 and so on.

    – kang
    yesterday















    No problem. Use TreeMap or LinkedHashMap instead.

    – oleg.cherednik
    yesterday





    No problem. Use TreeMap or LinkedHashMap instead.

    – oleg.cherednik
    yesterday













    Mistyped earlier comment. Not sure if you read it fully.

    – kang
    yesterday





    Mistyped earlier comment. Not sure if you read it fully.

    – kang
    yesterday













    Fixed. Not output matches with expectations.

    – oleg.cherednik
    yesterday





    Fixed. Not output matches with expectations.

    – oleg.cherednik
    yesterday











    0














    You can try below




    1. Add all items from 1st List to 3rd List

    2. Compare 2nd & 3rd Lists and remove the common items or the condition (see compareTo method in Fruit Class)

    3. If Items are removed from 3rd List add the same item from 2nd to 3rd List


    Please see the code below,



    finalList.addAll(firstList);
    for (Fruit secondfruit : secondList) {
    boolean isRemoved = finalList.removeIf(firstfruit -> firstfruit.compareTo(secondfruit) == 0);
    if(isRemoved) {
    finalList.add(secondfruit);
    }
    }
    for (Fruit fruit : finalList) {
    System.out.println(fruit.getName());
    }


    Fruit class with Comparable,



    class Fruit implements Comparable<Fruit> {
    private String id;
    private String name;
    private boolean isChecked;

    @Override
    public int compareTo(Fruit o) {
    if (o.isChecked && this.id.equalsIgnoreCase(o.id)) {
    return 0;
    }
    else {
    return 1;
    }
    }
    }


    Result is,
    f1
    f3
    f4
    f2
    f5






    share|improve this answer


























    • Hi, I get what you are doing. But I believe I would lose order in this way. if(isRemoved) {finalList.add(secondfruit);} This got added to the end of the list when it should have climbed up the order. Can't add to index 0 either since the item at that index may already have isChecked.

      – kang
      yesterday











    • Result should be f2, f5, f1, f3, f4

      – kang
      yesterday
















    0














    You can try below




    1. Add all items from 1st List to 3rd List

    2. Compare 2nd & 3rd Lists and remove the common items or the condition (see compareTo method in Fruit Class)

    3. If Items are removed from 3rd List add the same item from 2nd to 3rd List


    Please see the code below,



    finalList.addAll(firstList);
    for (Fruit secondfruit : secondList) {
    boolean isRemoved = finalList.removeIf(firstfruit -> firstfruit.compareTo(secondfruit) == 0);
    if(isRemoved) {
    finalList.add(secondfruit);
    }
    }
    for (Fruit fruit : finalList) {
    System.out.println(fruit.getName());
    }


    Fruit class with Comparable,



    class Fruit implements Comparable<Fruit> {
    private String id;
    private String name;
    private boolean isChecked;

    @Override
    public int compareTo(Fruit o) {
    if (o.isChecked && this.id.equalsIgnoreCase(o.id)) {
    return 0;
    }
    else {
    return 1;
    }
    }
    }


    Result is,
    f1
    f3
    f4
    f2
    f5






    share|improve this answer


























    • Hi, I get what you are doing. But I believe I would lose order in this way. if(isRemoved) {finalList.add(secondfruit);} This got added to the end of the list when it should have climbed up the order. Can't add to index 0 either since the item at that index may already have isChecked.

      – kang
      yesterday











    • Result should be f2, f5, f1, f3, f4

      – kang
      yesterday














    0












    0








    0







    You can try below




    1. Add all items from 1st List to 3rd List

    2. Compare 2nd & 3rd Lists and remove the common items or the condition (see compareTo method in Fruit Class)

    3. If Items are removed from 3rd List add the same item from 2nd to 3rd List


    Please see the code below,



    finalList.addAll(firstList);
    for (Fruit secondfruit : secondList) {
    boolean isRemoved = finalList.removeIf(firstfruit -> firstfruit.compareTo(secondfruit) == 0);
    if(isRemoved) {
    finalList.add(secondfruit);
    }
    }
    for (Fruit fruit : finalList) {
    System.out.println(fruit.getName());
    }


    Fruit class with Comparable,



    class Fruit implements Comparable<Fruit> {
    private String id;
    private String name;
    private boolean isChecked;

    @Override
    public int compareTo(Fruit o) {
    if (o.isChecked && this.id.equalsIgnoreCase(o.id)) {
    return 0;
    }
    else {
    return 1;
    }
    }
    }


    Result is,
    f1
    f3
    f4
    f2
    f5






    share|improve this answer















    You can try below




    1. Add all items from 1st List to 3rd List

    2. Compare 2nd & 3rd Lists and remove the common items or the condition (see compareTo method in Fruit Class)

    3. If Items are removed from 3rd List add the same item from 2nd to 3rd List


    Please see the code below,



    finalList.addAll(firstList);
    for (Fruit secondfruit : secondList) {
    boolean isRemoved = finalList.removeIf(firstfruit -> firstfruit.compareTo(secondfruit) == 0);
    if(isRemoved) {
    finalList.add(secondfruit);
    }
    }
    for (Fruit fruit : finalList) {
    System.out.println(fruit.getName());
    }


    Fruit class with Comparable,



    class Fruit implements Comparable<Fruit> {
    private String id;
    private String name;
    private boolean isChecked;

    @Override
    public int compareTo(Fruit o) {
    if (o.isChecked && this.id.equalsIgnoreCase(o.id)) {
    return 0;
    }
    else {
    return 1;
    }
    }
    }


    Result is,
    f1
    f3
    f4
    f2
    f5







    share|improve this answer














    share|improve this answer



    share|improve this answer








    edited yesterday

























    answered yesterday









    praba buddypraba buddy

    419618




    419618













    • Hi, I get what you are doing. But I believe I would lose order in this way. if(isRemoved) {finalList.add(secondfruit);} This got added to the end of the list when it should have climbed up the order. Can't add to index 0 either since the item at that index may already have isChecked.

      – kang
      yesterday











    • Result should be f2, f5, f1, f3, f4

      – kang
      yesterday



















    • Hi, I get what you are doing. But I believe I would lose order in this way. if(isRemoved) {finalList.add(secondfruit);} This got added to the end of the list when it should have climbed up the order. Can't add to index 0 either since the item at that index may already have isChecked.

      – kang
      yesterday











    • Result should be f2, f5, f1, f3, f4

      – kang
      yesterday

















    Hi, I get what you are doing. But I believe I would lose order in this way. if(isRemoved) {finalList.add(secondfruit);} This got added to the end of the list when it should have climbed up the order. Can't add to index 0 either since the item at that index may already have isChecked.

    – kang
    yesterday





    Hi, I get what you are doing. But I believe I would lose order in this way. if(isRemoved) {finalList.add(secondfruit);} This got added to the end of the list when it should have climbed up the order. Can't add to index 0 either since the item at that index may already have isChecked.

    – kang
    yesterday













    Result should be f2, f5, f1, f3, f4

    – kang
    yesterday





    Result should be f2, f5, f1, f3, f4

    – kang
    yesterday











    0














    Assume the firstList length is n,the secondList length is m,your can cost O(nlogn) + O(mlogm) +O(n+m) to solve the problem. The algorithm like merge sort.



    public static List<Fruit> merge(List<Fruit> list1, List<Fruit> list2) {
    // sort list1 and list2
    Comparator<Fruit> comparator = Comparator.comparingInt(o -> Integer.parseInt(o.getId()));
    Collections.sort(list1, comparator);
    Collections.sort(list2, comparator);

    List<Fruit> finalList1 = new ArrayList<>();
    List<Fruit> finalList2 = new ArrayList<>();
    int length1 = list1.size();
    int length2 = list2.size();
    int index1 = 0;
    int index2 = 0;

    while (index1 < length1 && index2 < length2) {
    Fruit fruit1 = list1.get(index1);
    Fruit fruit2 = list2.get(index2);
    if (fruit1.getId().equals(fruit2.getId()) && fruit2.isChecked()) {
    finalList2.add(fruit2);
    index2++;
    index1++;
    } else {
    finalList1.add(fruit1);
    index1++;
    }
    }

    while (index1 < length1) {
    finalList1.add(list1.get(index1));
    index1++;
    }

    finalList2.addAll(finalList1);
    return finalList2;
    }





    share|improve this answer




























      0














      Assume the firstList length is n,the secondList length is m,your can cost O(nlogn) + O(mlogm) +O(n+m) to solve the problem. The algorithm like merge sort.



      public static List<Fruit> merge(List<Fruit> list1, List<Fruit> list2) {
      // sort list1 and list2
      Comparator<Fruit> comparator = Comparator.comparingInt(o -> Integer.parseInt(o.getId()));
      Collections.sort(list1, comparator);
      Collections.sort(list2, comparator);

      List<Fruit> finalList1 = new ArrayList<>();
      List<Fruit> finalList2 = new ArrayList<>();
      int length1 = list1.size();
      int length2 = list2.size();
      int index1 = 0;
      int index2 = 0;

      while (index1 < length1 && index2 < length2) {
      Fruit fruit1 = list1.get(index1);
      Fruit fruit2 = list2.get(index2);
      if (fruit1.getId().equals(fruit2.getId()) && fruit2.isChecked()) {
      finalList2.add(fruit2);
      index2++;
      index1++;
      } else {
      finalList1.add(fruit1);
      index1++;
      }
      }

      while (index1 < length1) {
      finalList1.add(list1.get(index1));
      index1++;
      }

      finalList2.addAll(finalList1);
      return finalList2;
      }





      share|improve this answer


























        0












        0








        0







        Assume the firstList length is n,the secondList length is m,your can cost O(nlogn) + O(mlogm) +O(n+m) to solve the problem. The algorithm like merge sort.



        public static List<Fruit> merge(List<Fruit> list1, List<Fruit> list2) {
        // sort list1 and list2
        Comparator<Fruit> comparator = Comparator.comparingInt(o -> Integer.parseInt(o.getId()));
        Collections.sort(list1, comparator);
        Collections.sort(list2, comparator);

        List<Fruit> finalList1 = new ArrayList<>();
        List<Fruit> finalList2 = new ArrayList<>();
        int length1 = list1.size();
        int length2 = list2.size();
        int index1 = 0;
        int index2 = 0;

        while (index1 < length1 && index2 < length2) {
        Fruit fruit1 = list1.get(index1);
        Fruit fruit2 = list2.get(index2);
        if (fruit1.getId().equals(fruit2.getId()) && fruit2.isChecked()) {
        finalList2.add(fruit2);
        index2++;
        index1++;
        } else {
        finalList1.add(fruit1);
        index1++;
        }
        }

        while (index1 < length1) {
        finalList1.add(list1.get(index1));
        index1++;
        }

        finalList2.addAll(finalList1);
        return finalList2;
        }





        share|improve this answer













        Assume the firstList length is n,the secondList length is m,your can cost O(nlogn) + O(mlogm) +O(n+m) to solve the problem. The algorithm like merge sort.



        public static List<Fruit> merge(List<Fruit> list1, List<Fruit> list2) {
        // sort list1 and list2
        Comparator<Fruit> comparator = Comparator.comparingInt(o -> Integer.parseInt(o.getId()));
        Collections.sort(list1, comparator);
        Collections.sort(list2, comparator);

        List<Fruit> finalList1 = new ArrayList<>();
        List<Fruit> finalList2 = new ArrayList<>();
        int length1 = list1.size();
        int length2 = list2.size();
        int index1 = 0;
        int index2 = 0;

        while (index1 < length1 && index2 < length2) {
        Fruit fruit1 = list1.get(index1);
        Fruit fruit2 = list2.get(index2);
        if (fruit1.getId().equals(fruit2.getId()) && fruit2.isChecked()) {
        finalList2.add(fruit2);
        index2++;
        index1++;
        } else {
        finalList1.add(fruit1);
        index1++;
        }
        }

        while (index1 < length1) {
        finalList1.add(list1.get(index1));
        index1++;
        }

        finalList2.addAll(finalList1);
        return finalList2;
        }






        share|improve this answer












        share|improve this answer



        share|improve this answer










        answered yesterday









        TongChenTongChen

        27529




        27529






























            draft saved

            draft discarded




















































            Thanks for contributing an answer to Stack Overflow!


            • Please be sure to answer the question. Provide details and share your research!

            But avoid



            • Asking for help, clarification, or responding to other answers.

            • Making statements based on opinion; back them up with references or personal experience.


            To learn more, see our tips on writing great answers.




            draft saved


            draft discarded














            StackExchange.ready(
            function () {
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f54251146%2fefficiently-compare-2-lists-to-replace-and-order%23new-answer', 'question_page');
            }
            );

            Post as a guest















            Required, but never shown





















































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown

































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown







            Popular posts from this blog

            Liquibase includeAll doesn't find base path

            How to use setInterval in EJS file?

            Petrus Granier-Deferre