/*
Copyright 1996-2008 Ariba, Inc.
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.
$Id: //ariba/platform/util/core/ariba/util/core/SubsetIterator.java#3 $
*/
package ariba.util.core;
import java.util.Iterator;
import java.util.NoSuchElementException;
/**
A SubsetIterator produces a series of subsets of the requested size
from a source array of objects.
@aribaapi ariba
*/
public final class SubsetIterator implements Iterator
{
/*-----------------------------------------------------------------------
Private Fields
-----------------------------------------------------------------------*/
// source array
private Object[] _source;
private int _sourceSize;
// results array
private Object[] _result;
private int _resultSize;
// source index for each result element
private int[] _index;
// is our next result ready?
private boolean _nextReady = true;
/*-----------------------------------------------------------------------
Public Constructor
-----------------------------------------------------------------------*/
/**
Creates a new SubsetIterator for the given <b>source</b> array,
where each subset will be of the given <b>subsetSize</b>.
*/
public SubsetIterator (Object[] source, int subsetSize)
{
this(source, subsetSize, new Object[subsetSize]);
}
/**
Creates a new SubsetIterator for the given <b>source</b> array,
where each subset will be of the given <b>subsetSize</b>. The
caller provides the <b>result</b> array which will be returned in
each successful call to next().
*/
public SubsetIterator (Object[] source, int subsetSize, Object[] result)
{
// bail out if the subsetSize is invalid
if ((subsetSize <= 0) || (subsetSize > source.length)) {
return;
}
// make sure the result array is big enough
Assert.that(subsetSize <= result.length, "result array too small");
// cache our source array and its size
_source = source;
_sourceSize = source.length;
// cache our result array and its size
_result = result;
_resultSize = subsetSize;
// initialize our indexes and the first result subset
_index = new int[_resultSize];
for (int i = 0; i < _resultSize; i++) {
_index[i] = i;
_result[i] = _source[i];
}
}
/*-----------------------------------------------------------------------
Iterator Interface
-----------------------------------------------------------------------*/
/**
Returns true if the SubsetIterator has more elements.
*/
public boolean hasNext ()
{
if (_nextReady) {
return true;
}
int n;
int j;
int t;
for (int i = _resultSize - 1; i >= 0; --i) {
n = _index[i];
if ((n - i + _resultSize) < _sourceSize) {
for (j = i; j < _resultSize; ++j) {
_index[j] = t = ++n;
_result[j] = _source[t];
}
_nextReady = true;
return true;
}
}
return false;
}
/**
Returns the next element of this SubsetIterator as an array of
Objects. Throws a NoSuchElementException if there is no next
elemement, i.e. if hasNext() returned false.
*/
public Object next ()
{
if (_nextReady || hasNext()) {
_nextReady = false;
return _result;
}
else {
throw new NoSuchElementException();
}
}
public void remove ()
{
throw new UnsupportedOperationException();
}
/*-----------------------------------------------------------------------
Test Main
-----------------------------------------------------------------------*/
/**
The first argument is assumed to be an integer which is the requested
subset size. The remaining arguments are used as the elements of the
full set.
*/
public static void main (String[] args)
{
// first arg is the subset size
int size = new Integer(args[0]).intValue(); // OK
// set up the source array as everything but the first arg
Object[] source = new Object[args.length-1];
System.arraycopy(args, 1, source, 0, args.length-1);
long start = System.currentTimeMillis();
// run the subsets and print each one
SubsetIterator s = new SubsetIterator(source, size);
int count = 0;
Object result;
while (s.hasNext()) {
result = s.next();
printArray((Object[])result);
count++;
}
long end = System.currentTimeMillis();
Fmt.F(SystemUtil.out(),
"elapsed time is %s\n", Constants.getLong((end - start)));
Fmt.F(SystemUtil.out(), "There were %s subsets.", count);
Fmt.F(SystemUtil.out(), "there were %s enumerations per second",
Constants.getLong((count / (end-start) * 1000)));
SystemUtil.exit(0);
}
private static void printArray (Object[] objArray)
{
SystemUtil.out().print("( ");
for (int i = 0; i < objArray.length; i++) {
if (i > 0) {
SystemUtil.out().print(", ");
}
SystemUtil.out().print(objArray[i]);
}
SystemUtil.out().println(" )");
}
}