ListMerger.java
package access.manage;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
public class ListMerger {
private ListMerger() {
}
public static List<String> threeWayMerge(
List<String> base, // list1: original
List<String> left, // list2: your changes
List<String> right // list3: their changes
) {
// Compute diffs against the base
Map<Integer, String> leftChanges = diff(base, left);
Map<Integer, String> rightChanges = diff(base, right);
// Start from the longer of left/right to preserve additions
int maxSize = Math.max(left.size(), right.size());
List<String> result = new ArrayList<>();
for (int i = 0; i < maxSize; i++) {
boolean leftChanged = leftChanges.containsKey(i);
boolean rightChanged = rightChanges.containsKey(i);
if (leftChanged && rightChanged) {
String leftVal = leftChanges.get(i);
String rightVal = rightChanges.get(i);
if (Objects.equals(leftVal, rightVal)) {
// Both made the same change — no real conflict
if (leftVal != null) result.add(leftVal);
} else if (i >= base.size()) {
// ✅ CHANGED: both added different items past the end of base — keep both
if (leftVal != null) result.add(leftVal);
if (rightVal != null) result.add(rightVal);
} else {
// True conflict on an existing line: prefer left
if (leftVal != null) {
result.add(leftVal);
}
}
} else if (leftChanged) {
// Only left modified this index
String val = leftChanges.get(i);
if (val != null) result.add(val); // null = deleted
} else if (rightChanged) {
// Only right modified this index
String val = rightChanges.get(i);
if (val != null) result.add(val); // null = deleted
} else {
// Neither side touched this index — take from base
if (i < base.size()) result.add(base.get(i));
}
}
return new LinkedHashSet<>(result).stream().toList();
}
/**
* Produces a map of { index → newValue } representing what changed.
* A null value means "deleted at this index".
* Indices beyond base.size() are pure additions.
*/
private static Map<Integer, String> diff(List<String> base, List<String> updated) {
Map<Integer, String> changes = new HashMap<>();
int maxLen = Math.max(base.size(), updated.size());
for (int i = 0; i < maxLen; i++) {
String baseVal = i < base.size() ? base.get(i) : null;
String updatedVal = i < updated.size() ? updated.get(i) : null;
if (!Objects.equals(baseVal, updatedVal)) {
changes.put(i, updatedVal); // null = deletion
}
}
return changes;
}
}