[COLLECTIONS-296] Renamed CollectionUtils.merge to collate, simplify implementation by using a CollatingIterator.

git-svn-id: https://svn.apache.org/repos/asf/commons/proper/collections/trunk@1476770 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Thomas Neidhart 2013-04-28 13:58:37 +00:00
parent 696c768716
commit c71a9e8c2b
3 changed files with 46 additions and 89 deletions

View File

@ -298,7 +298,7 @@
Calling "CollectionUtils#sizeIsEmpty(null)" will now return true.
</action>
<action issue="COLLECTIONS-296" dev="tn" type="add" due-to="Julius Davies">
Added methods "CollectionUtils#merge(...)" to merge two sorted Collections
Added methods "CollectionUtils#collate(...)" to merge two sorted Collections
into a sorted List using the standard O(n) merge algorithm.
</action>
<action issue="COLLECTIONS-294" dev="bayard" type="fix" due-to="Benjamin Bentmann">

View File

@ -38,6 +38,7 @@ import org.apache.commons.collections4.collection.UnmodifiableBoundedCollection;
import org.apache.commons.collections4.collection.UnmodifiableCollection;
import org.apache.commons.collections4.functors.Equator;
import org.apache.commons.collections4.functors.TruePredicate;
import org.apache.commons.collections4.iterators.CollatingIterator;
import org.apache.commons.collections4.iterators.PermutationIterator;
/**
@ -1498,9 +1499,9 @@ public class CollectionUtils {
* @throws IllegalArgumentException if either collection is null
* @since 4.0
*/
public static <O extends Comparable<? super O>> List<O> merge(Collection<? extends O> a,
Collection<? extends O> b) {
return merge(a, b, ComparatorUtils.<O>naturalComparator(), true);
public static <O extends Comparable<? super O>> List<O> collate(Collection<? extends O> a,
Collection<? extends O> b) {
return collate(a, b, ComparatorUtils.<O>naturalComparator(), true);
}
/**
@ -1519,10 +1520,10 @@ public class CollectionUtils {
* @throws IllegalArgumentException if either collection is null
* @since 4.0
*/
public static <O extends Comparable<? super O>> List<O> merge(final Collection<? extends O> a,
final Collection<? extends O> b,
final boolean includeDuplicates) {
return merge(a, b, ComparatorUtils.<O>naturalComparator(), includeDuplicates);
public static <O extends Comparable<? super O>> List<O> collate(final Collection<? extends O> a,
final Collection<? extends O> b,
final boolean includeDuplicates) {
return collate(a, b, ComparatorUtils.<O>naturalComparator(), includeDuplicates);
}
/**
@ -1539,9 +1540,9 @@ public class CollectionUtils {
* @throws IllegalArgumentException if either collection or the comparator is null
* @since 4.0
*/
public static <O> List<O> merge(final Collection<? extends O> a, final Collection<? extends O> b,
final Comparator<? super O> c) {
return merge(a, b, c, true);
public static <O> List<O> collate(final Collection<? extends O> a, final Collection<? extends O> b,
final Comparator<? super O> c) {
return collate(a, b, c, true);
}
/**
@ -1560,8 +1561,8 @@ public class CollectionUtils {
* @throws IllegalArgumentException if either collection or the comparator is null
* @since 4.0
*/
public static <O> List<O> merge(final Collection<? extends O> a, final Collection<? extends O> b,
final Comparator<? super O> c, final boolean includeDuplicates) {
public static <O> List<O> collate(final Collection<? extends O> a, final Collection<? extends O> b,
final Comparator<? super O> c, final boolean includeDuplicates) {
if (a == null || b == null) {
throw new IllegalArgumentException("The collections must not be null");
@ -1570,68 +1571,24 @@ public class CollectionUtils {
throw new IllegalArgumentException("The comparator must not be null");
}
final List<O> mergedList = new ArrayList<O>(a.size() + b.size());
// if either collection is empty, just return the other one
if (a.isEmpty() || b.isEmpty()) {
mergedList.addAll(a.isEmpty() ? b : a);
return mergedList;
}
final Iterator<? extends O> it1 = a.iterator();
final Iterator<? extends O> it2 = b.iterator();
O o1 = it1.next();
O o2 = it2.next();
O last = null;
while (true) {
final int x = c.compare(o1, o2);
if (x <= 0) {
last = addItemToList(o1, mergedList, last, includeDuplicates);
if (it1.hasNext()) {
o1 = it1.next();
} else {
// a is empty, so add current element of b
last = addItemToList(o2, mergedList, last, includeDuplicates);
break;
}
} else {
last = addItemToList(o2, mergedList, last, includeDuplicates);
if (it2.hasNext()) {
o2 = it2.next();
} else {
// b is empty, so add current element of a
last = addItemToList(o1, mergedList, last, includeDuplicates);
break;
}
}
}
// add the remaining elements from the non-empty iterator
final Iterator<? extends O> it = it1.hasNext() ? it1 : it2;
while (it.hasNext()) {
last = addItemToList(it.next(), mergedList, last, includeDuplicates);
}
return mergedList;
}
/**
* Adds an item to the specified list.
*
* @param item the item to add
* @param list the list to use
* @param lastItem the last added item, may be null
* @param includeDuplicates whether duplicate entries are allowed
* @return the last added item
* @since 4.0
*/
private static <E> E addItemToList(final E item, final List<E> list, final E lastItem,
final boolean includeDuplicates) {
if (includeDuplicates || lastItem == null || !lastItem.equals(item)) {
list.add(item);
return item;
final int totalSize = Math.max(1, a.size() + b.size());
final Iterator<O> iterator = new CollatingIterator<O>(c, a.iterator(), b.iterator());
if (includeDuplicates) {
return IteratorUtils.toList(iterator, totalSize);
} else {
return lastItem;
final ArrayList<O> mergedList = new ArrayList<O>(totalSize);
O lastItem = null;
while (iterator.hasNext()) {
final O item = iterator.next();
if (lastItem == null || !lastItem.equals(item)) {
mergedList.add(item);
}
lastItem = item;
}
mergedList.trimToSize();
return mergedList;
}
}

View File

@ -1640,25 +1640,25 @@ public class CollectionUtilsTest extends MockTestCase {
}
@Test(expected=IllegalArgumentException.class)
public void mergeException1() {
CollectionUtils.merge(collectionA, null);
public void collateException1() {
CollectionUtils.collate(collectionA, null);
}
@Test(expected=IllegalArgumentException.class)
public void mergeException2() {
CollectionUtils.merge(collectionA, collectionC, null);
public void collateException2() {
CollectionUtils.collate(collectionA, collectionC, null);
}
@Test
public void testMerge() {
List<Integer> result = CollectionUtils.merge(emptyCollection, emptyCollection);
public void testCollate() {
List<Integer> result = CollectionUtils.collate(emptyCollection, emptyCollection);
assertEquals("Merge empty with empty", 0, result.size());
result = CollectionUtils.merge(collectionA, emptyCollection);
result = CollectionUtils.collate(collectionA, emptyCollection);
assertEquals("Merge empty with non-empty", collectionA, result);
List<Integer> result1 = CollectionUtils.merge(collectionD, collectionE);
List<Integer> result2 = CollectionUtils.merge(collectionE, collectionD);
List<Integer> result1 = CollectionUtils.collate(collectionD, collectionE);
List<Integer> result2 = CollectionUtils.collate(collectionE, collectionD);
assertEquals("Merge two lists 1", result1, result2);
List<Integer> combinedList = new ArrayList<Integer>();
@ -1671,23 +1671,23 @@ public class CollectionUtilsTest extends MockTestCase {
final Comparator<Integer> reverseComparator =
ComparatorUtils.reversedComparator(ComparatorUtils.<Integer>naturalComparator());
result = CollectionUtils.merge(emptyCollection, emptyCollection, reverseComparator);
result = CollectionUtils.collate(emptyCollection, emptyCollection, reverseComparator);
assertEquals("Comparator Merge empty with empty", 0, result.size());
Collections.reverse((List<Integer>) collectionD);
Collections.reverse((List<Integer>) collectionE);
Collections.reverse(combinedList);
result1 = CollectionUtils.merge(collectionD, collectionE, reverseComparator);
result2 = CollectionUtils.merge(collectionE, collectionD, reverseComparator);
result1 = CollectionUtils.collate(collectionD, collectionE, reverseComparator);
result2 = CollectionUtils.collate(collectionE, collectionD, reverseComparator);
assertEquals("Comparator Merge two lists 1", result1, result2);
assertEquals("Comparator Merge two lists 2", combinedList, result2);
}
@Test
public void testMergeIgnoreDuplicates() {
List<Integer> result1 = CollectionUtils.merge(collectionD, collectionE, false);
List<Integer> result2 = CollectionUtils.merge(collectionE, collectionD, false);
public void testCollateIgnoreDuplicates() {
List<Integer> result1 = CollectionUtils.collate(collectionD, collectionE, false);
List<Integer> result2 = CollectionUtils.collate(collectionE, collectionD, false);
assertEquals("Merge two lists 1 - ignore duplicates", result1, result2);
Set<Integer> combinedSet = new HashSet<Integer>();