Index: src/test/org/apache/commons/collections/TestSortedUtils.java =================================================================== --- src/test/org/apache/commons/collections/TestSortedUtils.java (revision 0) +++ src/test/org/apache/commons/collections/TestSortedUtils.java (revision 0) @@ -0,0 +1,168 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections; + +import junit.framework.Test; +import junit.framework.TestCase; +import junit.framework.TestSuite; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Comparator; +import java.util.LinkedList; +import java.util.List; + +/** + * Tests for SortedUtils. + * + * @author juliusdavies@gmail.com + */ +public class TestSortedUtils extends TestCase { + + public TestSortedUtils(String testName) { + super(testName); + } + + public static Test suite() { + return new TestSuite(TestSortedUtils.class); + } + + public static void main(String args[]) { + String[] testCaseName = {TestSortedUtils.class.getName()}; + junit.textui.TestRunner.main(testCaseName); + } + + private Collection collA = null; + private Collection collB = null; + private Collection collC = null; + private Collection collD = null; + private Collection collE = null; + private Collection collF = null; + private Object objX = "x"; + private Object nullObj = null; + private Collection nullColl = null; + private Collection emptyColl = new ArrayList(); + private Comparator reverseComparator = + ComparatorUtils.reversedComparator(ComparatorUtils.NATURAL_COMPARATOR); + + + public void setUp() { + collA = new ArrayList(); + collA.add("a"); + collA.add("b"); + collA.add("b"); + collA.add("c"); + collA.add("c"); + collA.add("c"); + collA.add("d"); + collA.add("d"); + collA.add("d"); + collA.add("d"); + collB = new LinkedList(); + collB.add("e"); + collB.add("d"); + collB.add("d"); + collB.add("c"); + collB.add("c"); + collB.add("c"); + collB.add("b"); + collB.add("b"); + collB.add("b"); + collB.add("b"); + + collC = new ArrayList(); + collC.add("v"); + collC.add("x"); + collC.add("z"); + collD = new LinkedList(); + collD.add("w"); + collD.add("y"); + collE = new ArrayList(); + collE.add("v"); + collE.add("w"); + collE.add("x"); + collE.add("y"); + collE.add("z"); + collF = new ArrayList(); + collF.add("w"); + collF.add("x"); + collF.add("y"); + } + + public void testMerge() { + ArrayList result1; + ArrayList result2; + int n; + + assertNull("Merge two nulls", SortedUtils.merge(nullObj, nullColl)); + + n = SortedUtils.merge(nullObj, emptyColl).size(); + assertEquals("Merge null with empty", 0, n); + + n = SortedUtils.merge(emptyColl, emptyColl).size(); + assertEquals("Merge empty with empty", 0, n); + + result1 = SortedUtils.merge(collA, emptyColl); + assertTrue("Merge empty with non-empty", collA.equals(result1)); + + result1 = SortedUtils.merge(objX, collD); + assertTrue("Merge obj with list", collF.equals(result1)); + + result1 = SortedUtils.merge(collC, collD); + result2 = SortedUtils.merge(collD, collC); + assertTrue("Merge two lists 1", result1.equals(result2)); + assertTrue("Merge two lists 2", collE.equals(result2)); + + result1 = SortedUtils.merge(collA, collC); + result2 = new ArrayList(collA); + result2.addAll(collC); + assertTrue("Merge two lists 3", result1.equals(result2)); + + + assertNull("Comparator Merge two nulls", SortedUtils.merge(nullObj, nullColl, reverseComparator)); + + n = SortedUtils.merge(nullObj, emptyColl, reverseComparator).size(); + assertEquals("Comparator Merge null with empty", 0, n); + + n = SortedUtils.merge(emptyColl, emptyColl, reverseComparator).size(); + assertEquals("Comparator Merge empty with empty", 0, n); + + + Collections.reverse((List) collA); + Collections.reverse((List) collC); + Collections.reverse((List) collD); + Collections.reverse((List) collE); + Collections.reverse((List) collF); + + result1 = SortedUtils.merge(objX, collD, reverseComparator); + assertTrue("Comparator Merge obj with list", collF.equals(result1)); + + result1 = SortedUtils.merge(collC, collD, reverseComparator); + result2 = SortedUtils.merge(collD, collC, reverseComparator); + assertTrue("Comparator Merge two lists 1", result1.equals(result2)); + assertTrue("Comparator Merge two lists 2", collE.equals(result2)); + + result1 = SortedUtils.merge(collA, collC, reverseComparator); + result2 = new ArrayList(collC); + result2.addAll(collA); + assertTrue("Comparator Merge two lists 3", result1.equals(result2)); + + } + + +} Index: src/java/org/apache/commons/collections/SortedUtils.java =================================================================== --- src/java/org/apache/commons/collections/SortedUtils.java (revision 0) +++ src/java/org/apache/commons/collections/SortedUtils.java (revision 0) @@ -0,0 +1,147 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Comparator; +import java.util.Iterator; + +/** + * Utility methods for dealing with sorted Collections. + * + * @author juliusdavies@gmail.com + */ +public class SortedUtils { + + + private static ArrayList toList(Object o) { + if (o == null) { + return null; + } else if (o instanceof ArrayList) { + return (ArrayList) o; + } else if (o instanceof Collection) { + return new ArrayList((Collection) o); + } else { + ArrayList a = new ArrayList(); + a.add(o); + return a; + } + } + + /** + * Returns a new ArrayList where Object a and sorted Collection b + * are combined such that the natural ordering of the elements + * is retained. Uses the standard O(n) merge algorithm for combining + * two sorted lists. + * + * @param a Object to combine with sorted Collection b. Must implement Comparable. + * @param b Sorted Collection to combine with Object a. + * @return a new sorted ArrayList + */ + public static ArrayList merge(Object a, Collection b) { + return merge(toList(a), b, null); + } + + /** + * Returns a new ArrayList where Object a and sorted Collection b + * are combined such that ordering of the elements according to + * Comparator c is retained. Uses the standard O(n) merge algorithm + * for combining two sorted lists. + * + * @param a Object to combine with sorted Collection b. Must implement Comparable. + * @param b Sorted Collection to combine with Object a. + * @param c Comparator by which Collection b has been sorted, or null + * if the Collection is sorted according to its natural ordering. + * @return a new sorted ArrayList + */ + public static ArrayList merge(Object a, Collection b, Comparator c) { + return merge(toList(a), b, c); + } + + /** + * Returns a new ArrayList sorted Collection a and sorted Collection b + * are combined such that the natural ordering of the elements + * is retained. Uses the standard O(n) merge algorithm for combining + * two sorted lists. + * + * @param a Sorted Collection to combine with sorted Collection b. + * The elements of each Collection must implement Comparable. + * @param b Sorted Collection to combine with sorted Collection a. + * The elements of each Collection must implement Comparable. + * @return a new sorted ArrayList + */ + public static ArrayList merge(Collection a, Collection b) { + return merge(a, b, null); + } + + /** + * Returns a new ArrayList where sorted Collection a and sorted Collection b + * are combined such that ordering of the elements according to + * Comparator c is retained. Uses the standard O(n) merge algorithm + * for combining two sorted lists. + * + * @param a Object to combine with sorted Collection b. Must implement Comparable. + * @param b Sorted Collection to combine with Object a. + * @param c Comparator by which Collection a and Collection b have been sorted, or null + * if the Collections are sorted according to their natural ordering. + * @return a new sorted ArrayList + */ + public static ArrayList merge(Collection a, Collection b, Comparator c) { + if (a == null || a.isEmpty()) { return toList(b); } + if (b == null || b.isEmpty()) { return toList(a); } + if (c == null) { c = ComparatorUtils.NATURAL_COMPARATOR; } + + ArrayList merge = new ArrayList(a.size() + b.size()); + Iterator it1 = a.iterator(); + Iterator it2 = b.iterator(); + Object o1 = it1.next(); + Object o2 = it2.next(); + int x = c.compare(o1, o2); + while (true) { + if (x <= 0) { + merge.add(o1); + if (it1.hasNext()) { + o1 = it1.next(); + } else { + // a is empty, so add rest of b + merge.add(o2); + while (it2.hasNext()) { + merge.add(it2.next()); + } + break; + } + } else { + merge.add(o2); + if (it2.hasNext()) { + o2 = it2.next(); + } else { + // b is empty, so add rest of a + merge.add(o1); + while (it1.hasNext()) { + merge.add(it1.next()); + } + break; + } + } + x = c.compare(o1, o2); + } + return merge; + } + + +}