Home > Net >  Add 2 list of objects and remove duplicate(all but one field different) elements from the final list
Add 2 list of objects and remove duplicate(all but one field different) elements from the final list

Time:06-13

I have a object class like

class Device{
String name;
String type;
String status;
}

I have 2 lists 1st one is like {d1,m1,active}, {d2,m2,active},{d3,m3,acticve}

2nd one {d2,m2,paused},{d4,m4,paused}

i want my final list to be like {d1,m1,active},{d2,m2,paused},{d3,m3,active},{d4,m4,paused}

My approach was to make a list of commonName{d2} then add both the list{d1,d2,d2,d3,d4} into a total list and then iterate through the total list and if the common deviceName(d2.contains(i.getName())) matches then remove the one with the status active(By remove i mean make another list and dont add the "Active" object).

Is there an efficient way of doing this other than using contains inside a iteration. Reducing the complexity to o(N).

CodePudding user response:

If the 2 lists are ordered by name you can do a merge-like operation without any contains operations. I'll write the code in python because I haven't written in java for some time, if you have hard time translating it to java just write a comment and I'll rewrite it:

merged = []
i = 0
j = 0
while i < len(lst1) and j < len(lst2):
    if lst1[i] < lst2[j]:
        merged.append(lst1[i])
        i  = 1
    # if lst2[j] == lst1[i] you want to take the paused one (in lst2)
    else: 
        merged.append(lst2[j])
        j  = 1

    # Advance i and j so there will not be duplicates
    while lst1[i] == merged[-1]:
        i  = 1
    while lst2[j] == merged[-1]:
        j  = 1

# Only one of these loops will run
while i < len(lst1):
    merged.append(lst1[i])
    i  = 1
while j < len(lst2):
    merged.append(lst2[j])
    j  = 1

CodePudding user response:

I couldn't find automatized way to let Java resolve it for you so I wrote this code thinking on the efficience.

What it does is use a java.util.Set in order to find the elements faster than java.util.List and implemented the hashcode and equals of the bean object to determine if the objects are equals.

In only one pass you are able to find a duplicate Item, check its status and overwrite it if needed. If you have active items in both lists you maybe need to add one more check in the if inside the loop.

That is the result produced.

Item{name='d1', type='m1', status='active'}

Item{name='d2', type='m2', status='paused'}

Item{name='d3', type='m3', status='active'}

Item{name='d4', type='m4', status='paused'}

public class MergeList {
    public static void main(String[] args) {
        List<Item> list1 = new ArrayList<>();
        list1.add(new Item("d1", "m1", "active"));
        list1.add(new Item("d2", "m2", "active"));
        list1.add(new Item("d3", "m3", "active"));

        List<Item> list2 = new ArrayList<>();
        list2.add(new Item("d2", "m2", "paused"));
        list2.add(new Item("d4", "m4", "paused"));

        Set<Item> listResult = new HashSet<>();
        listResult.addAll(list1);

        for(Item i : list2) {
            if (listResult.contains(i) && "active".equals(i.getStatus()))
                continue;

            listResult.remove(i);
            listResult.add(i);
        }

        for(Item i : listResult)
            System.out.println(i);
    }
}

class Item {

    private String name;
    private String type;
    private String status;
    
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Item item = (Item) o;
        return name.equals(item.name);
    }

    @Override
    public int hashCode() {
        return Objects.hash(name);
    }

    public Item(String name, String type, String status) {
        this.name = name;
        this.type = type;
        this.status = status;
    }

    //getter and setters
}

CodePudding user response:

Assuming the divices in first list have unique names you can stream over both list and collect to map merging whenever found same name in second list chosing the one having paused as status. Example using following class as sample:

@ToString
@AllArgsConstructor
@Getter
static class Divice {
    private String name;
    private String type;
    private String status;
}

and following sample lists

List<Divice> list1 = new ArrayList<>();
list1.add(new Divice("d1", "m1", "active"));
list1.add(new Divice("d2", "m2", "active"));
list1.add(new Divice("d3", "m3", "active"));

List<Divice> list2 = new ArrayList<>();
list2.add(new Divice("d2", "m2", "paused"));
list2.add(new Divice("d4", "m4", "paused"));

then do :

List<Divice> merged = new ArrayList<>(
        Stream.concat(list1.stream(),list2.stream())
                .collect(Collectors.toMap(Divice::getName,
                                          Function.identity(),
                                          (i,j) -> "paused".equals(i.getStatus()) ? i : j,
                                          LinkedHashMap::new)).values()
);

merged.forEach(System.out::println);
  • Related