/** * Copyright 2012 Oak Ridge National Laboratory * Author: James Horey <horeyjl@ornl.gov> * * Licensed 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 gov.ornl.keva.core; /** * Java libs. **/ import java.util.Iterator; import java.util.Comparator; import java.util.List; import java.util.ArrayList; /** * Merge multiple, sorted iterators into a single iterator. This iterator * returns values in sorted order across iterators assuming that the user * supplies a comparator. This iterator is also special in that users can * define equivalence classes. Values within a single equivalence class can * be "merged" so that only a single value is returned. * * @author James Horey */ public class MergeSortedIterator<E> extends StreamIterator<E> { private List<StreamIterator<E>> iters; private List<E> index; private int size; /** * @param iterators The iterators containing all the values. Assumes that these * values are already sorted within a single iterator. * @param comparator Compare two values * @param equivOp Define an equivalence between values */ public MergeSortedIterator(Comparator<E> comparator) { super(comparator); } public void addAll(List<StreamIterator<E>> iterators) { this.iters = iterators; // Populate the index with null values for each slot. index = new ArrayList<>(iters.size()); for(int i = 0; i < iters.size(); ++i) { index.add(null); } // Now populate the index with initial iterator values. int i = 0; for(StreamIterator<E> iter : iters) { size += iter.size(); placeIntoSlot(iter, index, i++); } } /** * Get the number of elements being processed. */ @Override public int size() { return size; } /** * Helper method to place the next value from the iterator * into the appropriate slot. **/ private void placeIntoSlot(Iterator<E> iter, List<E> index, int mySlot) { if(iter.hasNext()) { E v = iter.next(); index.set(mySlot, v); } else { // There are no more values in this iterator. index.set(mySlot,null); } } /** * Indicate whether we have another element. * * @return True if there is another value. False otherwise. */ @Override public boolean hasNext() { // Check if there are any values left. for(int i = 0; i < iters.size(); ++i) { if(index.get(i) != null) { return true; } } return false; } /** * Fetch the next element. * * @return Next value in the iterator. */ @Override public E next() { // Go through all the values in the current set, and // choose the one with the least value (according to whatever // comparator is used). Afterwards, re-populate that slot. E least = null; int leastIndex = 0; for(int i = 0; i < iters.size(); ++i) { if(index.get(i) != null) { if(least == null) { least = index.get(i); leastIndex = i; } else { if(comparator == null) { // The user is not interesed in sorting the values. least = index.get(i); leastIndex = i; break; } else if(comparator.compare(least, index.get(i)) > 0) { // Only choose the least value. least = index.get(i); leastIndex = i; } } } } // Fill up the used slot. placeIntoSlot(iters.get(leastIndex), index, leastIndex); // Return the least value. return least; } /** * Remove current element (not implemented). */ @Override public void remove() { // Do not implement. } }