/**
*
* Copyright (c) 2006-2017, Speedment, Inc. All Rights Reserved.
*
* 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.speedment.common.combinatorics.internal;
import com.speedment.common.combinatorics.*;
import java.util.*;
import java.util.stream.LongStream;
import java.util.stream.Stream;
/**
* General Permutation support from
* http://minborgsjavapot.blogspot.com/2015/07/java-8-master-permutations.html
*
* @author Per Minborg
*/
public final class PermutationUtil {
public static long factorial(final int n) {
if (n > 20 || n < 0) {
throw new IllegalArgumentException(n + " is out of range");
}
return LongStream.rangeClosed(2, n).reduce(1, (a, b) -> a * b);
}
public static <T> List<T> permutation(final long no, final List<T> items) {
return permutationHelper(no,
new LinkedList<>(Objects.requireNonNull(items)),
new ArrayList<>());
}
private static <T> List<T> permutationHelper(final long no, final LinkedList<T> in, final List<T> out) {
if (in.isEmpty()) {
return out;
}
final long subFactorial = factorial(in.size() - 1);
out.add(in.remove((int) (no / subFactorial)));
return permutationHelper((int) (no % subFactorial), in, out);
}
@SafeVarargs
@SuppressWarnings("varargs") // Creating a List from an array is safe
public static <T> Stream<Stream<T>> of(final T... items) {
final List<T> itemList = Arrays.asList(items);
return LongStream.range(0, factorial(items.length))
.mapToObj(no -> permutation(no, itemList).stream());
}
private PermutationUtil() {
throw new UnsupportedOperationException();
}
}