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