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

com.github.davidmoten.rx.internal.operators.Permutations Maven / Gradle / Ivy

package com.github.davidmoten.rx.internal.operators;

import java.util.Iterator;
import java.util.List;

public final class Permutations {

    private Permutations() {
        // prevent instantiation
    }

    public static  Iterable> iterable(final List list) {
        return new Iterable>() {
            @Override
            public Iterator> iterator() {
                return new PermutationsSwapIterator(list);
            }
        };
    }

    public static  Iterator> iterator(List list) {
        return new PermutationsSwapIterator(list);
    }

    private static class PermutationsSwapIterator implements Iterator> {

        /**
         * After
         * http://www.cut-the-knot.org/Curriculum/Combinatorics/JohnsonTrotter.
         * shtml
         * 
         */
        private final T[] values;
        private final DirectedReference[] references;

        @SuppressWarnings("unchecked")
        public PermutationsSwapIterator(List list) {
            this.values = (T[]) list.toArray();
            this.references = new DirectedReference[list.size()];
            for (int i = 0; i < this.references.length; i++) {
                this.references[i] = new DirectedReference(-1, i);
            }
        }

        private boolean isMobile(int index) {
            if (index == 0 && references[index].direction == -1) {
                return false;
            } else if (index == references.length - 1 && references[index].direction == 1) {
                return false;
            } else if (references[index
                    + references[index].direction].reference > references[index].reference) {
                return false;
            } else {
                return true;
            }
        }

        @Override
        public boolean hasNext() {
            for (int i = 0; i < references.length; i++) {
                if (isMobile(i)) {
                    return true;
                }
            }
            return false;
        }

        @Override
        public Swap next() {
            // find the largest mobile reference "chosen"
            int chosen = Integer.MIN_VALUE;
            int chosenIndex = -1;
            for (int i = 0; i < references.length; i++) {
                if (isMobile(i) && references[i].reference > chosen) {
                    chosen = references[i].reference;
                    chosenIndex = i;
                }
            }

            // swaps it in the indicated direction
            int neighbourIndex = chosenIndex + references[chosenIndex].direction;
            Swap swap = new Swap(values[references[chosenIndex].reference],
                    values[references[neighbourIndex].reference]);

            DirectedReference tmp = references[chosenIndex];
            references[chosenIndex] = references[neighbourIndex];
            references[neighbourIndex] = tmp;

            // reverse the direction of all references larger than "chosen"
            for (int i = 0; i < references.length; i++) {
                if (references[i].reference > chosen) {
                    references[i].reverse();
                }
            }

            return swap;
        }

        @Override
        public void remove() {
            throw new UnsupportedOperationException("cannot remove from permutations");
        }

    }

    public static class Swap {
        private final T left;
        private final T right;

        Swap(T left, T right) {
            this.left = left;
            this.right = right;
        }

        public T left() {
            return left;
        }

        public T right() {
            return right;
        }

        @Override
        public String toString() {
            return "Swap [left=" + left + ", right=" + right + "]";
        }

    }

    private static class DirectedReference {
        private final int reference;
        private int direction;

        DirectedReference(int direction, int reference) {
            this.direction = direction;
            this.reference = reference;
        }

        public void reverse() {
            this.direction = -this.direction;
        }

        @Override
        public String toString() {
            String val = String.valueOf(reference);
            String result = direction == -1 ? "<" + val : val + ">";
            return result + String.valueOf(reference);
        }
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy