ProjectAres/Util/core/src/main/java/tc/oc/commons/core/util/C3.java

69 lines
2.2 KiB
Java

package tc.oc.commons.core.util;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Objects;
import com.google.common.collect.ImmutableList;
import tc.oc.commons.core.ListUtils;
public class C3 {
private C3() {}
/**
* Merge the given lists into a single list using the C3 linearization algorithm
* https://en.wikipedia.org/wiki/C3_linearization
*
* This algorithm is commonly used to flatten multi-parent inheritance trees into
* a single ancestral line.
*/
public static <T> List<? extends T> merge(Collection<Collection<? extends T>> parents) {
final List<List<? extends T>> lists = new ArrayList<>();
for(Collection<? extends T> parent : parents) {
if(!parent.isEmpty()) {
lists.add(new ArrayList<>(parent));
}
}
final ImmutableList.Builder<T> merged = ImmutableList.builder();
outerLoop: while(!lists.isEmpty()) {
for(List<? extends T> list : lists) {
final T head = list.get(0);
if(!anyTailsContain(lists, head)) {
merged.add(head);
removeHeads(lists, head);
removeEmpty(lists);
continue outerLoop;
}
}
throw new IllegalArgumentException("Unable to merge lists due to ordering conflict");
}
return merged.build();
}
private static <T> boolean anyTailsContain(List<List<? extends T>> lists, T element) {
for(List<? extends T> list : lists) {
if(ListUtils.contains(list, element, 1)) return true;
}
return false;
}
private static <T> void removeHeads(List<List<? extends T>> lists, T element) {
for(List<? extends T> list : lists) {
if(Objects.equals(list.get(0), element)) {
list.remove(0);
}
}
}
private static <T> void removeEmpty(List<List<? extends T>> lists) {
for(Iterator<List<? extends T>> iterator = lists.iterator(); iterator.hasNext(); ) {
if(iterator.next().isEmpty()) iterator.remove();
}
}
}