RegionZipper { public static <S extends GenomeRegion, T extends GenomeRegion> void zip(@NotNull List<S> primary, @NotNull List<T> secondary, @NotNull RegionZipperHandler<S, T> handler) { String chromosome = ""; int i = 0, j = 0; while (i < primary.size() || j < secondary.size()) { S leftRegion = i < primary.size() ? primary.get(i) : null; T rightRegion = j < secondary.size() ? secondary.get(j) : null; if (leftRegion == null || (rightRegion != null && compare(leftRegion, rightRegion) > 0)) { assert rightRegion != null; if (!rightRegion.chromosome().equals(chromosome)) { chromosome = rightRegion.chromosome(); handler.enterChromosome(chromosome); } handler.secondary(rightRegion); j++; } else { if (!leftRegion.chromosome().equals(chromosome)) { chromosome = leftRegion.chromosome(); handler.enterChromosome(chromosome); } handler.primary(leftRegion); i++; } } } private  RegionZipper(); static void zip(@NotNull List<S> primary, @NotNull List<T> secondary,
            @NotNull RegionZipperHandler<S, T> handler);  }
@Test public void testZipper() { final List<GenomeRegion> primary = Lists.newArrayList(GenomeRegions.create("1", 1, 100), GenomeRegions.create("1", 500, 1000), GenomeRegions.create("2", 500, 1000), GenomeRegions.create("4", 500, 1000)); final List<GenomeRegion> secondary = Lists.newArrayList( GenomeRegions.create("1", 500, 1000), GenomeRegions.create("2", 500, 1000), GenomeRegions.create("3", 500, 1000)); new Expectations() {{ handler.enterChromosome("1"); handler.primary(primary.get(0)); handler.primary(primary.get(1)); handler.secondary(secondary.get(0)); handler.enterChromosome("2"); handler.primary(primary.get(2)); handler.secondary(secondary.get(1)); handler.enterChromosome("3"); handler.secondary(secondary.get(2)); handler.enterChromosome("4"); handler.primary(primary.get(3)); }}; RegionZipper.zip(primary, secondary, handler); }