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

de.spricom.dessert.util.CombinationUtils Maven / Gradle / Ivy

The newest version!
package de.spricom.dessert.util;

/*-
 * #%L
 * Dessert Dependency Assertion Library for Java
 * %%
 * Copyright (C) 2017 - 2023 Hans Jörg Heßmann
 * %%
 * 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.
 * #L%
 */

import java.util.*;

public class CombinationUtils {

    public static  List> combinationsAsList(final List list) {
        return asList(combinations(list), combinations(list.size()));
    }

    public static  List> combinationsSortedAsList(final List list) {
        return asList(combinationsSorted(list), combinationsSorted(list.size()));
    }

    private static  List> asList(Iterable> iter, int capacity) {
        List> results = new ArrayList>(capacity);
        for (Pair tPair : iter) {
            results.add(tPair);
        }
        return results;
    }

    public static  Iterable> combinations(final List list) {
        return new Iterable>() {
            @Override
            public Iterator> iterator() {
                return both(pairs(list));
            }
        };
    }

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

    public static List indexes(int size) {
        Integer[] indexes = new Integer[size];
        for (int i = 0; i < size; i++) {
            indexes[i] = i;
        }
        return Arrays.asList(indexes);
    }

    private static  Iterator> both(final Iterator> pairs) {
        return new PermutationIterator() {
            private Pair current;

            @Override
            public boolean hasNext() {
                return current != null || pairs.hasNext();
            }

            @Override
            public Pair next() {
                if (current == null) {
                    current = pairs.next();
                    return current;
                } else {
                    Pair other = new Pair(current.getRight(), current.getLeft());
                    current = null;
                    return other;
                }
            }
        };
    }

    private static  Iterator> pairs(final List list) {
        final int sz = list.size();
        if (sz < 2) {
            throw new IllegalArgumentException("A list must contain at least 2 elements to create a permutation.");
        }
        if (sz == 2) {
            return Collections.singleton(new Pair(list.get(0), list.get(1))).iterator();
        }
        return new PermutationIterator() {
            private final T first = list.get(0);
            private int index = 1;
            private Iterator> rest;

            @Override
            public boolean hasNext() {
                return index < sz || rest().hasNext();
            }

            @Override
            public Pair next() {
                if (index < sz) {
                    Pair result = new Pair(first, list.get(index));
                    index++;
                    return result;
                }
                return rest().next();
            }

            private Iterator> rest() {
                if (rest == null) {
                    rest = pairs(list.subList(1, sz));
                }
                return rest;
            }
        };
    }

    public static int combinations(int n) {
        return combinationsSorted(n) * 2;
    }

    public static int combinationsSorted(int n) {
        return binominal(n, 2);
    }

    /**
     * Calculates @{code factorial(n) / (factorial(k) * factorial(n - k))}.
     *
     * @param n number of different values
     * @param k number of slots
     * @return number of possible combinations
     */
    public static int binominal(int n, int k) {
        if (k * 2 > n) {
            k = n - k;
        }
        int result = 1;
        for (int i = 1; i <= k; i++) {
            result = result * (n + 1 - i) / i;
        }
        return result;
    }

    public static int factorial(final int n) {
        if (n < 0) {
            throw new IllegalArgumentException("Factorial for negative numbers is not defined");
        }
        if (n <= 1) {
            return 1;
        }
        long result = 1;
        for (int i = 2; i <= n; i++) {
            result = result * i;
            if (result > Integer.MAX_VALUE) {
                throw new IllegalArgumentException("Factorial of " + n + " does not fit into an integer.");
            }
        }
        return (int)result;
    }

    static abstract class PermutationIterator implements Iterator> {

        @Override
        public void remove() {
            throw new UnsupportedOperationException("Cannot remove elements from permutation.");
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy