diff --git a/java/src/org/broadinstitute/sting/utils/MergingIterator.java b/java/src/org/broadinstitute/sting/utils/MergingIterator.java new file mode 100644 index 000000000..45db41558 --- /dev/null +++ b/java/src/org/broadinstitute/sting/utils/MergingIterator.java @@ -0,0 +1,109 @@ +package org.broadinstitute.sting.utils; + +import org.broadinstitute.sting.gatk.iterators.PeekingIterator; +import org.broadinstitute.sting.gatk.refdata.ReferenceOrderedDatum; + +import java.util.*; + +public class MergingIterator> implements Iterator, PeekingIterator, Iterable { + PriorityQueue queue = new PriorityQueue(); + + private class Element implements Comparable { + public Iterator it = null; + public E value = null; + + public Element(Iterator it) { + this.it = it; + update(); + } + + public Element update() { + if ( ! it.hasNext() ) + throw new RuntimeException("it is empty"); + + E prev = value; + value = it.next(); + //System.out.printf("Updating %s to prev=%s, next=%s%n", this, prev, value); + return this; + } + + public int compareTo(Element other) { + return value.compareTo(other.value); + } + } + + public Iterator iterator() { + return this; + } + + public MergingIterator() { + ; + } + + public MergingIterator(Iterator it) { + add(it); + } + + public MergingIterator(Collection> its) { + for ( Iterator it : its ) { + add(it); + } + } + + public void add(Iterator it) { + if ( it.hasNext() ) + queue.add(new Element(it)); + } + + public boolean hasNext() { + return ! queue.isEmpty(); + } + + public E next() { + Element e = queue.poll(); + E value = e.value; + + if ( e.it != null && e.it.hasNext() ) + queue.add(new Element(e.it)); + + //System.out.printf("Element is %s%n", e.value); + return value; + } + + public E peek() { + return queue.peek().value; + } + + public Collection allElementsLTE(E elt) { + return allElementsLTE(elt, true); + } + + public Collection allElementsLTE(E elt, boolean includeElt) { + LinkedList all = new LinkedList(); + + if ( includeElt ) all.add(elt); + + while ( hasNext() ) { + E x = peek(); + //System.out.printf("elt.compareTo(x) == %d%n", elt.compareTo(x)); + //System.out.printf("In allElementLTE%n"); + int cmp = elt.compareTo(x); + //System.out.printf("x=%s%n elt=%s%n => elt.compareTo(x) == %d%n", x, elt, cmp); + if ( cmp >= 0 ) { + //System.out.printf(" Adding element x=%s, size = %d%n", x, all.size()); + all.add(next()); + //System.out.printf(" Added size = %d%n", all.size()); + } + else { + //System.out.printf("breaking...%n"); + break; + } + } + + return all; + } + + public void remove() { + throw new UnsupportedOperationException(); + } +} diff --git a/java/test/org/broadinstitute/sting/utils/MergingIteratorTest.java b/java/test/org/broadinstitute/sting/utils/MergingIteratorTest.java new file mode 100644 index 000000000..a35e8d102 --- /dev/null +++ b/java/test/org/broadinstitute/sting/utils/MergingIteratorTest.java @@ -0,0 +1,119 @@ +// our package +package org.broadinstitute.sting.utils; + + +// the imports for unit testing. + +import org.junit.Assert; +import org.junit.Test; +import org.junit.Before; +import org.broadinstitute.sting.BaseTest; +import org.broadinstitute.sting.gatk.walkers.recalibration.RecalData; +import org.broadinstitute.sting.utils.QualityUtils; + +import java.util.*; + +/** + * Basic unit test for RecalData + */ +public class MergingIteratorTest extends BaseTest { + List one_to_ten = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); + List evens = Arrays.asList(2, 4, 6, 8, 10); + List three_four_five = Arrays.asList(3, 4, 5); + List bigs = Arrays.asList(100, 200, 500); + + MergingIterator x = null; + + @Before + public void before() { + x = null; + } + + @Test + public void testOneToOne() { + logger.warn("Executing testOneToOne"); + + x = new MergingIterator(one_to_ten.iterator()); + + for ( int i = 1; i < 11; i++ ) { + int elt = x.next(); + logger.warn(String.format("Testing %d == %d", i, elt)); + Assert.assertEquals(elt, i); + } + Assert.assertFalse(x.hasNext()); + } + + @Test + public void testMerging10Evens() { + logger.warn("Executing testMerging10Evens"); + + x = new MergingIterator(one_to_ten.iterator()); + x.add(evens.iterator()); + List expected = Arrays.asList(1, 2, 2, 3, 4, 4, 5, 6, 6, 7, 8, 8, 9, 10, 10); + + testExpected( x, expected ); + Assert.assertFalse(x.hasNext()); + } + + @Test + public void testMerging3() { + logger.warn("Executing testMerging3"); + + x = new MergingIterator(Arrays.asList(bigs.iterator(), evens.iterator(), three_four_five.iterator())); + List expected = Arrays.asList(2, 3, 4, 4, 5, 6, 8, 10, 100, 200, 500); + + testExpected( x, expected ); + Assert.assertFalse(x.hasNext()); + } + + @Test + public void testCollectLTE() { + logger.warn("Executing testCollectLTE"); + + x = new MergingIterator(Arrays.asList(bigs.iterator(), evens.iterator(), three_four_five.iterator())); + + //for ( int i : x ) { + // System.out.printf("i=%d%n", i); + //} + + logger.warn("Testing next element..."); + Assert.assertEquals( 2, (int)x.next()); + logger.warn("Testing allElementsLTE(2) = 2 ..."); + assertListsEqual( x.allElementsLTE(2), Arrays.asList(2) ); + + logger.warn("Testing allElementsLTE(3) = 3 ..."); + Assert.assertEquals(3, (int)x.next()); + assertListsEqual( x.allElementsLTE(3), Arrays.asList(3) ); + + logger.warn("Testing allElementsLTE(4) = 4, 4 ..."); + Assert.assertEquals(4, (int)x.next()); + assertListsEqual( x.allElementsLTE(4), Arrays.asList(4, 4) ); + + logger.warn("Testing allElementsLTE(8) = 5, 6, 8 ..."); + assertListsEqual( x.allElementsLTE(8, false), Arrays.asList(5, 6, 8) ); + + logger.warn("Testing remaining..."); + testExpected( x, Arrays.asList(10, 100, 200, 500) ); + Assert.assertFalse(x.hasNext()); + } + + private void testExpected( MergingIterator mi, List expected ) { + for ( int expect : expected ) { + int elt = mi.next(); + logger.warn(String.format("Testing elt=%d == expected=%d", elt, expect)); + Assert.assertEquals(expect, elt); + } + } + + private void assertListsEqual( Collection l, List expected ) { + logger.warn("Size is " + l.size()); + Iterator lit = l.iterator(); + + for ( int expect : expected ) { + Assert.assertTrue(lit.hasNext()); + int elt = lit.next(); + logger.warn(String.format("Testing elt=%d == expected=%d", elt, expect)); + Assert.assertEquals(expect, elt); + } + } +} \ No newline at end of file