Here you can find the source of computeCrossProduct(List extends Collection
Parameter | Description |
---|---|
E | The element type of the inner lists. |
allArgPossibilities | A list of lists containing the elements for the cross product. |
maximumSize | a parameter |
public static <E> List<List<E>> computeCrossProduct(List<? extends Collection<E>> allArgPossibilities, int maximumSize)
//package com.java2s; //License from project: Open Source License import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.Random; public class Main { /** The random instance for all the random utility functions. */ // TODO clean up so that the random instance is robust to multiple runs private static Random randomInstance = new Random(112957); /**// w w w .jav a 2s .c o m * Create the cross product of a list of list. I.e., { {a,b}, {c, d} -> { * {a,c}, {a,d}, {b,c}, {b,d} }. Since this is general-purpose utility, it * has been placed here. If this causes memory-usage problems, convert to an * iterative version. * * @param <E> * The element type of the inner lists. * @param allArgPossibilities * A list of lists containing the elements for the cross product. * @param maximumSize * @parem maximumSize * The maximum size of the result. Items will be randomly deleted. * @return A list containing the cross product of the given lists. */ public static <E> List<List<E>> computeCrossProduct(List<? extends Collection<E>> allArgPossibilities, int maximumSize) { // NOTE: do not use Set<List<E>> since DUPLICATES will be removed. // Here are some calculations for reducing the size of the cross-product set "as we go" (rather than during post-processing). // Li is the number of items that are expected to be produced after set i is recursively merged in. // L1 = maximumSize // Pi is the probability that an item in set i is added. // L1 = P1 x S1 x L2 // L2 is the reduced set that comes from the first recursive call. // L2 = P2 x S2 x L3 // L3 second // ... // Ln = Pn x Sn // The bottoming-out of the recursion. // After some algebra: // P1 x P2 x ... x Pn = L1 / (S1 x S2 x ... Sn) // If we let Pi = Q / Si, where Q is the Nth root of L1, then we get what we want. // Note: we ignore SINGLETON sets in the calculation (i.e., of 'n'), since they don't impact size. if (maximumSize < 1) { return null; } double Q = -1.0; if (maximumSize < Integer.MAX_VALUE) { int size = 1; int counter = 0; for (Collection<E> possibilities : allArgPossibilities) { size *= possibilities.size(); if (possibilities.size() > 1) { counter++; } } if (size > maximumSize) { Q = Math.pow(maximumSize, 1.0 / counter); } } return computeCrossProduct(allArgPossibilities, Q); } /** * See computeCrossProduct(List<Collection<E>> allArgPossibilities, int maximumSize) * In this version, maximumSize defaults to infinity. * * @param <E> * @param allArgPossibilities * @return */ public static <E> List<List<E>> computeCrossProduct(List<? extends Collection<E>> allArgPossibilities) { return computeCrossProduct(allArgPossibilities, Integer.MAX_VALUE); } private static <E> List<List<E>> computeCrossProduct(List<? extends Collection<E>> allArgPossibilities, double Q) { if (allArgPossibilities == null) { return null; } int length = allArgPossibilities.size(); if (length < 1) { return null; } List<List<E>> allArgPossibilitiesForRest = null; Collection<E> firstCollection = allArgPossibilities.get(0); int sizeOfFirstCollection = firstCollection.size(); if (length > 1) { allArgPossibilitiesForRest = computeCrossProduct(allArgPossibilities.subList(1, length), Q); // Of the results of the recursion, about probOfRandomlyDiscarding * sizeOfFirstList } List<List<E>> results = new ArrayList<List<E>>(4); double prob = Q / sizeOfFirstCollection; for (E term : firstCollection) { // For each choice for the first argument, ... if (allArgPossibilitiesForRest != null) { for (List<E> restArgs : allArgPossibilitiesForRest) { // ... combine with each possible choice for the rest of the args. List<E> args = new ArrayList<E>(1 + restArgs.size()); args.add(term); args.addAll(restArgs); if (Q < 0.0 || sizeOfFirstCollection <= 1 || random() < prob) { results.add(args); } } } else { // No choices for the rest of the list, so wrap each choice for the first of the list (could save some new'ing if the first list is of length one, but that would make this code more complicated). List<E> args = new ArrayList<E>(1); args.add(term); results.add(args); } } return results; } /** * @return The next random double. */ public static double random() { return randomInstance.nextDouble(); } }