[COLLECTIONS-456] Added ListUtils.longestCommonSubsequence(List, List).
git-svn-id: https://svn.apache.org/repos/asf/commons/proper/collections/trunk@1477312 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
72f33c83d4
commit
969ffdbb98
|
@ -22,6 +22,9 @@
|
||||||
<body>
|
<body>
|
||||||
|
|
||||||
<release version="4.0" date="TBA" description="Next release">
|
<release version="4.0" date="TBA" description="Next release">
|
||||||
|
<action issue="COLLECTIONS-456" dev="tn" type="add">
|
||||||
|
Added method "ListUtils#longestCommonSubsequence(List, List)".
|
||||||
|
</action>
|
||||||
<action issue="COLLECTIONS-454" dev="tn" type="update">
|
<action issue="COLLECTIONS-454" dev="tn" type="update">
|
||||||
An iterator over a "Flat3Map#entrySet()" will now return
|
An iterator over a "Flat3Map#entrySet()" will now return
|
||||||
independent Map.Entry objects that will not change anymore when
|
independent Map.Entry objects that will not change anymore when
|
||||||
|
@ -135,7 +138,7 @@
|
||||||
</action>
|
</action>
|
||||||
<action issue="COLLECTIONS-404" dev="luc" type="add" due-to="Jordane Sarda">
|
<action issue="COLLECTIONS-404" dev="luc" type="add" due-to="Jordane Sarda">
|
||||||
Added an implementation of Eugene Myers difference algorithm in package
|
Added an implementation of Eugene Myers difference algorithm in package
|
||||||
o.a.c.c.comparators.sequence.
|
o.a.c.c.sequence.
|
||||||
</action>
|
</action>
|
||||||
<action issue="COLLECTIONS-400" dev="tn" type="fix" due-to="Shin Hwei Tan">
|
<action issue="COLLECTIONS-400" dev="tn" type="fix" due-to="Shin Hwei Tan">
|
||||||
Added missing null check in "CollectionUtils#addIgnoreNull(Collection, Object)".
|
Added missing null check in "CollectionUtils#addIgnoreNull(Collection, Object)".
|
||||||
|
|
|
@ -30,6 +30,9 @@ import org.apache.commons.collections4.list.LazyList;
|
||||||
import org.apache.commons.collections4.list.PredicatedList;
|
import org.apache.commons.collections4.list.PredicatedList;
|
||||||
import org.apache.commons.collections4.list.TransformedList;
|
import org.apache.commons.collections4.list.TransformedList;
|
||||||
import org.apache.commons.collections4.list.UnmodifiableList;
|
import org.apache.commons.collections4.list.UnmodifiableList;
|
||||||
|
import org.apache.commons.collections4.sequence.CommandVisitor;
|
||||||
|
import org.apache.commons.collections4.sequence.EditScript;
|
||||||
|
import org.apache.commons.collections4.sequence.SequencesComparator;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provides utility methods and decorators for {@link List} instances.
|
* Provides utility methods and decorators for {@link List} instances.
|
||||||
|
@ -489,6 +492,7 @@ public class ListUtils {
|
||||||
return FixedSizeList.fixedSizeList(list);
|
return FixedSizeList.fixedSizeList(list);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------
|
||||||
/**
|
/**
|
||||||
* Finds the first index in the given List which matches the given predicate.
|
* Finds the first index in the given List which matches the given predicate.
|
||||||
* <p>
|
* <p>
|
||||||
|
@ -512,6 +516,53 @@ public class ListUtils {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------
|
||||||
|
/**
|
||||||
|
* Returns the longest common subsequence (LCS) of two sequences (lists).
|
||||||
|
*
|
||||||
|
* @param <T> the element type
|
||||||
|
* @param a the first list
|
||||||
|
* @param b the second list
|
||||||
|
* @return the longest common subsequence
|
||||||
|
* @throws IllegalArgumentException if either list is {@code null}
|
||||||
|
* @since 4.0
|
||||||
|
*/
|
||||||
|
public static <T> List<T> longestCommonSubsequence(final List<T> a, final List<T> b) {
|
||||||
|
if (a == null || b == null) {
|
||||||
|
throw new IllegalArgumentException("List must not be null");
|
||||||
|
}
|
||||||
|
|
||||||
|
final SequencesComparator<T> comparator = new SequencesComparator<T>(a, b);
|
||||||
|
final EditScript<T> script = comparator.getScript();
|
||||||
|
final LcsVisitor<T> visitor = new LcsVisitor<T>();
|
||||||
|
script.visit(visitor);
|
||||||
|
return visitor.getSubSequence();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A helper class used to construct the longest common subsequence.
|
||||||
|
*/
|
||||||
|
private static final class LcsVisitor<E> implements CommandVisitor<E> {
|
||||||
|
private ArrayList<E> sequence;
|
||||||
|
|
||||||
|
public LcsVisitor() {
|
||||||
|
sequence = new ArrayList<E>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void visitInsertCommand(final E object) {}
|
||||||
|
|
||||||
|
public void visitDeleteCommand(final E object) {}
|
||||||
|
|
||||||
|
public void visitKeepCommand(final E object) {
|
||||||
|
sequence.add(object);
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<E> getSubSequence() {
|
||||||
|
return sequence;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------
|
||||||
/**
|
/**
|
||||||
* Returns consecutive {@link List#subList(int, int) sublists} of a
|
* Returns consecutive {@link List#subList(int, int) sublists} of a
|
||||||
* list, each of the same size (the final list may be smaller). For example,
|
* list, each of the same size (the final list may be smaller). For example,
|
||||||
|
|
|
@ -31,6 +31,7 @@ import org.apache.commons.collections4.ListUtils;
|
||||||
import org.apache.commons.collections4.Predicate;
|
import org.apache.commons.collections4.Predicate;
|
||||||
import org.apache.commons.collections4.functors.EqualPredicate;
|
import org.apache.commons.collections4.functors.EqualPredicate;
|
||||||
import org.apache.commons.collections4.list.PredicatedList;
|
import org.apache.commons.collections4.list.PredicatedList;
|
||||||
|
import org.junit.Assert;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests for ListUtils.
|
* Tests for ListUtils.
|
||||||
|
@ -311,6 +312,46 @@ public class ListUtilsTest extends BulkTest {
|
||||||
assertEquals(ListUtils.indexOf(fullList, null), -1);
|
assertEquals(ListUtils.indexOf(fullList, null), -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void testLongestCommonSubsequence() {
|
||||||
|
|
||||||
|
try {
|
||||||
|
ListUtils.longestCommonSubsequence(null, null);
|
||||||
|
fail("failed to check for null argument");
|
||||||
|
} catch (final IllegalArgumentException e) {}
|
||||||
|
|
||||||
|
try {
|
||||||
|
ListUtils.longestCommonSubsequence(Arrays.asList('A'), null);
|
||||||
|
fail("failed to check for null argument");
|
||||||
|
} catch (final IllegalArgumentException e) {}
|
||||||
|
|
||||||
|
try {
|
||||||
|
ListUtils.longestCommonSubsequence(null, Arrays.asList('A'));
|
||||||
|
fail("failed to check for null argument");
|
||||||
|
} catch (final IllegalArgumentException e) {}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
List<Character> lcs = ListUtils.longestCommonSubsequence(Collections.EMPTY_LIST, Collections.EMPTY_LIST);
|
||||||
|
assertTrue(lcs.isEmpty());
|
||||||
|
|
||||||
|
List<Character> list1 = Arrays.asList('B', 'A', 'N', 'A', 'N', 'A');
|
||||||
|
List<Character> list2 = Arrays.asList('A', 'N', 'A', 'N', 'A', 'S');
|
||||||
|
lcs = ListUtils.longestCommonSubsequence(list1, list2);
|
||||||
|
|
||||||
|
List<Character> expected = Arrays.asList('A', 'N', 'A', 'N', 'A');
|
||||||
|
assertEquals(expected, lcs);
|
||||||
|
|
||||||
|
List<Character> list3 = Arrays.asList('A', 'T', 'A', 'N', 'A');
|
||||||
|
lcs = ListUtils.longestCommonSubsequence(list1, list3);
|
||||||
|
|
||||||
|
expected = Arrays.asList('A', 'A', 'N', 'A');
|
||||||
|
assertEquals(expected, lcs);
|
||||||
|
|
||||||
|
List<Character> listZorro = Arrays.asList('Z', 'O', 'R', 'R', 'O');
|
||||||
|
lcs = ListUtils.longestCommonSubsequence(list1, listZorro);
|
||||||
|
|
||||||
|
assertTrue(lcs.isEmpty());
|
||||||
|
}
|
||||||
|
|
||||||
public void testPartition() {
|
public void testPartition() {
|
||||||
final List<Integer> strings = new ArrayList<Integer>();
|
final List<Integer> strings = new ArrayList<Integer>();
|
||||||
for (int i = 0; i <= 6; i++) {
|
for (int i = 0; i <= 6; i++) {
|
||||||
|
|
Loading…
Reference in New Issue