/** * * 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.function.Consumer; import static java.util.stream.Collectors.toList; import java.util.stream.Stream; /** * General Combination support. The class eagerly calculates all combinations. * * @author Per Minborg */ public final class CombinationUtil { /** * Creates and returns all possible combinations of the given elements. * * The order of the combinations in the stream is unspecified. * * @param <T> element type * @param items to combine * @return all possible combinations of the given elements */ @SafeVarargs @SuppressWarnings("varargs") // Creating a List from an array is safe public static <T> Stream<List<T>> of(final T... items) { final Stream.Builder<List<T>> builder = Stream.builder(); final List<T> database = Arrays.asList(items); final List<T> buffer = new ArrayList<>(); database.stream().map(c -> (T) null).forEach(buffer::add); int k = database.size(); for (int i = 1; i <= k; i++) { generateCombinations(database, 0, i, buffer, l -> builder.add( l.stream() .filter(Objects::nonNull) .collect(toList()) )); } return builder.build(); } /** * Creates and returns all possible combinations of the given elements * whereby each element only occurs at most once in any given List. Elements * are checked for occurrence by its {@code equals() } method. * * The order of the combinations in the stream is unspecified. * * @param <T> element type * @param items to combine * @return all possible combinations of the given elements whereby each * element only occurs at most once in any given List */ @SafeVarargs @SuppressWarnings("varargs") // Creating a List from an array is safe public static <T> Stream<List<T>> ofDistinct(final T... items) { return of(items).filter(CombinationUtil::isDistinctElements); } private static <T> boolean isDistinctElements(List<T> list) { final Set<T> discovered = Collections.newSetFromMap(new HashMap<>()); return list.stream().allMatch(discovered::add); } private static <T> void generateCombinations(List<T> s, int i, int k, List<T> buff, Consumer<List<T>> consumer) { if (i < k) { for (int j = 0; j < s.size(); j++) { buff.set(i, s.get(j)); generateCombinations(s, i + 1, k, buff, consumer); } } else { consumer.accept(buff); } } private CombinationUtil() { throw new UnsupportedOperationException(); } }