Reputation: 113
I have 2 Lists:
// old list
List<Employee> oldList = new ArrayList<>();
Employee emp1 = new Employee();
emp1.setPersonalNumber("123");
emp1.setName("old_name1");
emp1.setStatus(Status.OLD);
Employee emp2 = new Employee();
emp2.setPersonalNumber("456");
emp2.setName("old_name2");
emp2.setStatus(Status.OLD);
oldList.add(emp1);
oldList.add(emp2);
// new list
List<Employee> newList = new ArrayList<>();
Employee newEmp1 = new Employee();
newEmp1.setPersonalNumber("123");
newEmp1.setName("new_name1");
newEmp1.setStatus(Status.NEW);
Employee newEmp2 = new Employee();
newEmp2.setPersonalNumber("456");
newEmp2.setName("new_name2");
newEmp2.setStatus(Status.NEW);
newList.add(newEmp1);
newList.add(newEmp2);
Does anyone know how can I merge those 2 Lists to one List containing all the employees from both lists grouped by "PersonalNumber" and keeping the order of the elemets in newList? newList comes from the Database with a predefined sorting, and I need to keep it that way, so I can't sort it again on the Java side
Result should be:
[
{"123", "new_name1", NEW},
{"123", "old_name1", OLD},
{"456", "new_name2", NEW},
{"456", "old_name1", OLD},
]
I have the guarantee that both lists have the same size and contain employees with the same personalNumbers. I just want to "inject" each old employee under the new employee with the same personalNumber
Upvotes: 4
Views: 2055
Reputation: 79025
You can do it as follows:
// Sort oldList on personalNumber for faster access when retrieving the records
// with same personalNumber
oldList.sort(Comparator.comparing(Employee::getPersonalNumber));
List<Employee> result = new ArrayList<Employee>();
for (int i = 0; i < newList.size(); i++) {
// Get an employee, `e` from `newList` and add to `result`
Employee e = newList.get(i);
result.add(e);
// Add elements from `newList` to `result` until a different `personalNumber`
// occurs
while (i < newList.size() - 1 && e.getPersonalNumber().equals(newList.get(i + 1).getPersonalNumber())) {
result.add(newList.get(++i));
}
// Iterate `oldList` to find an employee with the `personalNumber` equal to that
// of `e`
int j;
boolean found = false;
for (j = 0; j < oldList.size(); j++) {
if (oldList.get(j).getPersonalNumber().equals(e.getPersonalNumber())) {
found = true;
break;
}
}
// If `oldList` has an employee with the `personalNumber` equal to that of `e` ,
// add elements from `oldList` to `result` until a different `personalNumber`
// occurs. Note that `oldList` has already been sorted.
if (found) {
result.add(oldList.get(j));
while (j < oldList.size() - 1 && oldList.get(++j).getPersonalNumber().equals(e.getPersonalNumber())) {
result.add(oldList.get(j));
}
}
}
Demo:
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
enum Status {
OLD, NEW;
}
class Employee {
private String name;
private String personalNumber;
private Status status;
public Employee() {
super();
}
public Employee(String name, String personalNumber, Status status) {
this.name = name;
this.personalNumber = personalNumber;
this.status = status;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPersonalNumber() {
return personalNumber;
}
public void setPersonalNumber(String personalNumber) {
this.personalNumber = personalNumber;
}
public Status getStatus() {
return status;
}
public void setStatus(Status status) {
this.status = status;
}
@Override
public String toString() {
return personalNumber + ", " + name + ", " + status;
}
}
public class Main {
public static void main(String[] args) {
// old list
List<Employee> oldList = new ArrayList<Employee>();
Employee emp1 = new Employee();
emp1.setPersonalNumber("123");
emp1.setName("old_name1");
emp1.setStatus(Status.OLD);
Employee emp2 = new Employee();
emp2.setPersonalNumber("456");
emp2.setName("old_name2");
emp2.setStatus(Status.OLD);
oldList.add(emp1);
oldList.add(emp2);
// new list
List<Employee> newList = new ArrayList<>();
Employee newEmp1 = new Employee();
newEmp1.setPersonalNumber("123");
newEmp1.setName("new_name1");
newEmp1.setStatus(Status.NEW);
Employee newEmp2 = new Employee();
newEmp2.setPersonalNumber("456");
newEmp2.setName("new_name2");
newEmp2.setStatus(Status.NEW);
newList.add(newEmp1);
newList.add(newEmp2);
// Sort oldList on personalNumber for faster access when retrieving the records
// with same personalNumber
oldList.sort(Comparator.comparing(Employee::getPersonalNumber));
List<Employee> result = new ArrayList<Employee>();
for (int i = 0; i < newList.size(); i++) {
// Get an employee, `e` from `newList` and add to `result`
Employee e = newList.get(i);
result.add(e);
// Add elements from `newList` to `result` until a different `personalNumber`
// occurs
while (i < newList.size() - 1 && e.getPersonalNumber().equals(newList.get(i + 1).getPersonalNumber())) {
result.add(newList.get(++i));
}
// Iterate `oldList` to find an employee with the `personalNumber` equal to that
// of `e`
int j;
boolean found = false;
for (j = 0; j < oldList.size(); j++) {
if (oldList.get(j).getPersonalNumber().equals(e.getPersonalNumber())) {
found = true;
break;
}
}
// If `oldList` has an employee with the `personalNumber` equal to that of `e` ,
// add elements from `oldList` to `result` until a different `personalNumber`
// occurs. Note that `oldList` has already been sorted.
if (found) {
result.add(oldList.get(j));
while (j < oldList.size() - 1 && oldList.get(++j).getPersonalNumber().equals(e.getPersonalNumber())) {
result.add(oldList.get(j));
}
}
}
// Display the result
result.forEach(System.out::println);
}
}
Output:
123, new_name1, NEW
123, old_name1, OLD
456, new_name2, NEW
456, old_name2, OLD
Upvotes: 0
Reputation: 3323
Here is another approach with Java streams and InsStream
private List<Employee> mergeLists(List<Employee> oldList, List<Employee> newList) {
return IntStream.range(0, oldList.size())
.mapToObj(index -> Arrays.asList(newList.get(index), oldList.get(index)))
.flatMap(Collection::stream)
.collect(Collectors.toList());
}
This approach is possible because of
I have the guarantee that both lists have the same size and contain employees with the same personalNumbers.
Upvotes: 0
Reputation: 17289
You can do like this: As you mentioned that both lists have the same PersonalNumber so you can group by using this property. To ensure order based on the personalNumber
, I've used LinkedHashMap
.
Stream.concat(newList.stream(), oldList.stream())
.collect(Collectors.groupingBy(Employee::getPersonalNumber,
LinkedHashMap::new, Collectors.toList()))
.values().stream().flatMap(List::stream)
.collect(Collectors.toList());
Note: The result of stream#concat
is ordered if both of the input streams are ordered.
Upvotes: 4
Reputation: 12347
Collections to sort should work for this.
newList.addAll(oldList);
Collections.sort(newList, Comparator.comparing(Employee::getPersonalNumber) );
The key is that, "This sort is guaranteed to be stable: equal elements will not be reordered as a result of the sort."
Since cannot sort the new list, I take that to mean you don't know the order of the new list. You can do it the ol' N^2 method.
for(int i = 0; i<newList.size(); i+=2){
String newNum = newList.get(i).getPersonalNumber();
Employee old = oldList.stream().filter(
emp->newNum.equals(
emp.getPersonalNumber()
)
).findFirst().orElse(null);
newList.add(i+1, old);
oldList.remove(old); //not nescessary?
}
Upvotes: 3