All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.google.gwt.benchmarks.client.impl.PermutationIterator Maven / Gradle / Ivy

There is a newer version: 2.10.0
Show newest version
/*
 * Copyright 2008 Google 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.
 */
package com.google.gwt.benchmarks.client.impl;

import java.util.Iterator;
import java.util.List;
import java.util.ArrayList;
import java.util.Arrays;

/**
 * Iterates over all the possible permutations available in a list of {@link
 * Iterable Iterables}.
 * 
 * 

* The simplest way to iterate over the permutations of multiple iterators is in * a nested for loop. The PermutationIterator turns that for loop inside out * into a single iterator, which enables you to access each permutation in a * piecemeal fashion. *

*/ public class PermutationIterator implements Iterator { /** * A single permutation of all the iterators. Contains the current value of * each iterator for the permutation. */ public static class Permutation { private List values; public Permutation(List values) { this.values = new ArrayList(values); } public List getValues() { return values; } @Override public String toString() { return values.toString(); } } public static void main(String[] args) { List> iterables = new ArrayList>(3); iterables.add(Arrays.asList("a", "b", "c")); iterables.add(Arrays.asList("1", "2", "3")); iterables.add(Arrays.asList("alpha", "beta", "gamma", "delta")); System.out.println("Testing normal iteration."); for (Iterator it = new PermutationIterator(iterables); it.hasNext();) { Permutation p = it.next(); System.out.println(p); } System.out.println("\nTesting skipping iteration."); Iterator skipIterator = Arrays.asList("alpha", "beta", "gamma", "delta").iterator(); boolean skipped = true; String skipValue = null; for (PermutationIterator it = new PermutationIterator(iterables); it.hasNext();) { Permutation p = it.next(); if (skipped) { if (skipIterator.hasNext()) { skipValue = skipIterator.next(); skipped = false; } } System.out.println(p); Object value = p.getValues().get(p.getValues().size() - 1); if (value.equals(skipValue)) { it.skipCurrentRange(); skipped = true; } } } /** * Is this the first run? */ private boolean firstRun = true; /** * The iterator from every range. */ private List> iterators; /** * Are more permutations available? */ private boolean maybeHaveMore = true; /** * The {@code Iterables} to permute. */ private List> iterables; /** * Did we just skip a range? If so, the values List already contains the * values of the next permutation. */ private boolean rangeSkipped = false; /** * The current permutation of values. */ private List values; /** * Constructs a new PermutationIterator that provides the values for each * possible permutation of iterables. * * @param iterables non-null. Each {@link Iterable} must have at least one * element. iterables.size() must be > 1 * * TODO(tobyr) Consider if empty Iterables ever make sense in the context of * permutations. */ public PermutationIterator(List> iterables) { this.iterables = iterables; iterators = new ArrayList>(); for (Iterable iterable : iterables) { iterators.add(iterable.iterator()); } values = new ArrayList(); } /** * Returns a new Permutation containing the values of the next * permutation. * * @return a non-null Permutation */ public boolean hasNext() { if (!maybeHaveMore) { return false; } // Walk the iterators from bottom to top checking to see if any still have // any available values for (int currentIterator = iterators.size() - 1; currentIterator >= 0; --currentIterator) { Iterator it = iterators.get(currentIterator); if (it.hasNext()) { return true; } } return false; } public Permutation next() { assert hasNext() : "No more available permutations in this iterator."; if (firstRun) { // Initialize all of our iterators and values on the first run for (Iterator it : iterators) { values.add(it.next()); } firstRun = false; return new Permutation(values); } if (rangeSkipped) { rangeSkipped = false; return new Permutation(values); } // Walk through the iterators from bottom to top, finding the first one // which has a value available. Increment it, reset all of the subsequent // iterators, and then return the current permutation. for (int currentIteratorIndex = iterators.size() - 1; currentIteratorIndex >= 0; --currentIteratorIndex) { Iterator it = iterators.get(currentIteratorIndex); if (it.hasNext()) { values.set(currentIteratorIndex, it.next()); for (int i = currentIteratorIndex + 1; i < iterators.size(); ++i) { Iterable resetIterable = iterables.get(i); Iterator resetIterator = resetIterable.iterator(); iterators.set(i, resetIterator); values.set(i, resetIterator.next()); } return new Permutation(values); } } throw new AssertionError( "Assertion failed - Couldn't find a non-empty iterator."); } public void remove() { throw new UnsupportedOperationException(); } /** * Skips the remaining set of values in the bottom {@code Iterable}. This * method affects the results of both hasNext() and next(). */ public void skipCurrentRange() { rangeSkipped = true; for (int currentIteratorIndex = iterators.size() - 2; currentIteratorIndex >= 0; --currentIteratorIndex) { Iterator it = iterators.get(currentIteratorIndex); if (it.hasNext()) { values.set(currentIteratorIndex, it.next()); for (int i = currentIteratorIndex + 1; i < iterators.size(); ++i) { Iterable resetIterable = iterables.get(i); Iterator resetIterator = resetIterable.iterator(); iterators.set(i, resetIterator); values.set(i, resetIterator.next()); } return; } } maybeHaveMore = false; } }