Java 从多个列表生成所有组合

Java 从多个列表生成所有组合,java,list,algorithm,combinations,cartesian-product,Java,List,Algorithm,Combinations,Cartesian Product,给定未知数量的列表,每个列表的长度未知,我需要生成一个包含所有可能的唯一组合的单数列表。 例如,给定以下列表: X: [A, B, C] Y: [W, X, Y, Z] 那么我应该能够生成12个组合: [AW, AX, AY, AZ, BW, BX, BY, BZ, CW, CX, CY, CZ] 如果添加第三个包含3个元素的列表,我会有36个组合,以此类推 关于如何在Java中实现这一点,有什么想法吗? (伪代码也可以)使用其他答案提供的嵌套循环解决方案来组合两个列表 当您有两个以上的列

给定未知数量的列表,每个列表的长度未知,我需要生成一个包含所有可能的唯一组合的单数列表。 例如,给定以下列表:

X: [A, B, C] 
Y: [W, X, Y, Z]
那么我应该能够生成12个组合:

[AW, AX, AY, AZ, BW, BX, BY, BZ, CW, CX, CY, CZ]
如果添加第三个包含3个元素的列表,我会有36个组合,以此类推

关于如何在Java中实现这一点,有什么想法吗?

(伪代码也可以)

使用其他答案提供的嵌套循环解决方案来组合两个列表

当您有两个以上的列表时

  • 将前两个合并为一个新列表
  • 将结果列表与下一个输入列表合并
  • 重复一遍
  • 您需要递归:

    假设您的所有列表都在
    列表中,这是一个列表列表。让
    result
    成为所需排列的列表。您可以这样实现它:

    void generatePermutations(List<List<Character>> lists, List<String> result, int depth, String current) {
        if (depth == lists.size()) {
            result.add(current);
            return;
        }
    
        for (int i = 0; i < lists.get(depth).size(); i++) {
            generatePermutations(lists, result, depth + 1, current + lists.get(depth).get(i));
        }
    }
    
    generatePermutations(lists, result, 0, "");
    

    没有递归唯一的组合:

    [AW, AX, AY, AZ, BW, BX, BY, BZ, CW, CX, CY, CZ]
    
    stringsarray[]=新字符串[]{“A”、“A”、“B”、“C”};
    //将数组转换为列表
    List list1=Arrays.asList(sArray);
    List list2=Arrays.asList(sArray);
    List list3=Arrays.asList(sArray);
    LinkedList=新建LinkedList();
    列表。添加(列表1);
    列表。添加(列表2);
    列表。添加(列表3);
    集合组合=新树集合();
    设置新的二进制文件;
    for(字符串s:lists.removeFirst())
    组合。添加(s);
    而(!lists.isEmpty()){
    List next=lists.removeFirst();
    newCombinations=新树集();
    用于(字符串s1:组合)
    for(字符串s2:下一个)
    newCombinations.add(s1+s2);
    组合=新组合;
    }
    用于(字符串s:组合)
    系统输出打印(s+“”);
    
    这个话题很有用。我已经完全用Java重写了前面的解决方案,并且更加用户友好。此外,我使用集合和泛型以获得更大的灵活性:

    /**
     * Combines several collections of elements and create permutations of all of them, taking one element from each
     * collection, and keeping the same order in resultant lists as the one in original list of collections.
     * 
     * <ul>Example
     * <li>Input  = { {a,b,c} , {1,2,3,4} }</li>
     * <li>Output = { {a,1} , {a,2} , {a,3} , {a,4} , {b,1} , {b,2} , {b,3} , {b,4} , {c,1} , {c,2} , {c,3} , {c,4} }</li>
     * </ul>
     * 
     * @param collections Original list of collections which elements have to be combined.
     * @return Resultant collection of lists with all permutations of original list.
     */
    public static <T> Collection<List<T>> permutations(List<Collection<T>> collections) {
      if (collections == null || collections.isEmpty()) {
        return Collections.emptyList();
      } else {
        Collection<List<T>> res = Lists.newLinkedList();
        permutationsImpl(collections, res, 0, new LinkedList<T>());
        return res;
      }
    }
    
    /** Recursive implementation for {@link #permutations(List, Collection)} */
    private static <T> void permutationsImpl(List<Collection<T>> ori, Collection<List<T>> res, int d, List<T> current) {
      // if depth equals number of original collections, final reached, add and return
      if (d == ori.size()) {
        res.add(current);
        return;
      }
    
      // iterate from current collection and copy 'current' element N times, one for each element
      Collection<T> currentCollection = ori.get(d);
      for (T element : currentCollection) {
        List<T> copy = Lists.newLinkedList(current);
        copy.add(element);
        permutationsImpl(ori, res, d + 1, copy);
      }
    }
    
    /**
    *组合多个元素集合并创建所有元素的排列,从每个元素中提取一个元素
    *集合,并在结果列表中保持与原始集合列表中相同的顺序。
    * 
    *
      示例 *
    • Input={a,b,c},{1,2,3,4}
    • *
    • 输出={a,1},{a,2},{a,3},{a,4},{b,1},{b,3},{b,4},{c,1},{c,2},{c,3},{c,4}
    • *
    * *@param collections必须组合元素的集合的原始列表。 *@返回列表的结果集合以及原始列表的所有排列。 */ 公共静态集合排列(列表集合){ if(collections==null | | collections.isEmpty()){ 返回集合。emptyList(); }否则{ Collection res=Lists.newLinkedList(); 置换简单(集合,res,0,新LinkedList()); 返回res; } } /**{@link#置换(列表,集合)}的递归实现*/ 私有静态void置换simple(列表ori、集合res、int d、列表current){ //如果深度等于原始集合数,则添加并返回最终集合 如果(d==ori.size()){ res.add(当前); 返回; } //从当前集合迭代并复制“当前”元素N次,每个元素一次 Collection currentCollection=ori.get(d); 对于(T元素:currentCollection){ 列表副本=Lists.newLinkedList(当前); 复制。添加(元素); 置换单纯形(ori,res,d+1,copy); } }

    我正在使用guava library创建集合。

    添加了一个基于迭代器的答案,以用于通用列表
    列表
    ,扩展了Ruslan Ostafiichuk答案的思想。我的想法是:

    * List 1: [1 2]
    * List 2: [4 5]
    * List 3: [6 7]
    *
    * Take each element from list 1 and put each element
    * in a separate list.
    * combinations -> [ [1] [2] ]
    *
    * Set up something called newCombinations that will contains a list
    * of list of integers
    * Consider [1], then [2]
    *
    * Now, take the next list [4 5] and iterate over integers
    * [1]
    *  add 4   -> [1 4]
    *      add to newCombinations -> [ [1 4] ]
    *  add 5   -> [1 5]
    *      add to newCombinations -> [ [1 4] [1 5] ]
    *
    * [2]
    *  add 4   -> [2 4]
    *      add to newCombinations -> [ [1 4] [1 5] [2 4] ]
    *  add 5   -> [2 5]
    *      add to newCombinations -> [ [1 4] [1 5] [2 4] [2 5] ]
    *
    * point combinations to newCombinations
    * combinations now looks like -> [ [1 4] [1 5] [2 4] [2 5] ]
    * Now, take the next list [6 7] and iterate over integers
    *  ....
    *  6 will go into each of the lists
    *      [ [1 4 6] [1 5 6] [2 4 6] [2 5 6] ]
    *  7 will go into each of the lists
    *      [ [1 4 6] [1 5 6] [2 4 6] [2 5 6] [1 4 7] [1 5 7] [2 4 7] [2 5 7]]
    
    现在是代码。我使用
    集合
    只是为了消除任何重复项。可替换为
    列表
    。一切都应该天衣无缝地工作。:)

    publicstaticset-getcombines(列表){
    集合组合=新的HashSet();
    设置新的二进制文件;
    int指数=0;
    //提取第一个列表中的每个整数
    //并将其作为新列表添加到ints
    for(ti:list.get(0)){
    List newList=newarraylist();
    新列表。添加(i);
    组合。添加(新列表);
    }
    索引++;
    while(索引
    一块小试块

    publicstaticvoidmain(字符串[]args){
    列表l1=array.asList(1,2,3);
    listl2=Arrays.asList(4,5);
    listl3=Arrays.asList(6,7);
    List lists=新建ArrayList();
    列表。添加(l1);
    添加(l2);
    列表。添加(l3);
    设置梳=获取组合(列表);
    用于(列表:梳子){
    System.out.println(list.toString());
    }
    }
    
    • 无递归
    • 命令
    • 可以通过索引获得特定组合(无需构建所有其他排列):
    类和
    main()
    方法,最后:

    public class TwoDimensionalCounter<T> {
        private final List<List<T>> elements;
    
        public TwoDimensionalCounter(List<List<T>> elements) {
            this.elements = Collections.unmodifiableList(elements);
        }
    
        public List<T> get(int index) {
            List<T> result = new ArrayList<>();
            for(int i = elements.size() - 1; i >= 0; i--) {
                List<T> counter = elements.get(i);
                int counterSize = counter.size();
                result.add(counter.get(index % counterSize));
                index /= counterSize;
            }
            return result;//Collections.reverse() if you need the original order
        }
    
        public int size() {
            int result = 1;
            for(List<T> next: elements) result *= next.size();
            return result;
        }
    
        public static void main(String[] args) {
            TwoDimensionalCounter<Integer> counter = new TwoDimensionalCounter<>(
                    Arrays.asList(
                            Arrays.asList(1, 2, 3),
                            Arrays.asList(1, 2, 3),
                            Arrays.asList(1, 2, 3)
                    ));
            for(int i = 0; i < counter.size(); i++)
                System.out.println(counter.get(i));
        }
    }
    
    公共类二维计数器{
    私人最终清单要素;
    公共二维计数器(列表元素){
    this.elements=Collections.unmodifiableList(元素);
    }
    公共列表获取(int索引){
    列表结果=新建ArrayList();
    对于(int i=elements.size()-1;i>=0;i--){
    列表计数器=元素。获取(i);
    int counterSize=counter.size();
    result.add(counter.get(索引%counterSize));
    索引/=副标题;
    }
    返回结果;//如果需要原始顺序,则返回Collections.reverse()
    }
    公共整数大小(){
    int结果=1;
    for(List next:elements)result*=next.size();
    返回结果;
    }
    
    String[][] combinations = new String[][] {
                     new String[] { "0", "1" },
                     new String[] { "0", "1" },
                     new String[] { "0", "1" },
                     new String[] { "0", "1" } };
    
        int[] indices = new int[combinations.length];
        
        int currentIndex = indices.length - 1;
        outerProcess: while (true) {
    
            for (int i = 0; i < combinations.length; i++) {
                System.out.print(combinations[i][indices[i]]);
            }
            System.out.println();
    
            while (true) {
                // Increase current index
                indices[currentIndex]++;
                // If index too big, set itself and everything right of it to 0 and move left
                if (indices[currentIndex] >= combinations[currentIndex].length) {
                    for (int j = currentIndex; j < indices.length; j++) {
                        indices[j] = 0;
                    }
                    currentIndex--;
                } else {
                    // If index is allowed, move as far right as possible and process next
                    // combination
                    while (currentIndex < indices.length - 1) {
                        currentIndex++;
                    }
                    break;
                }
                // If we cannot move left anymore, we're finished
                if (currentIndex == -1) {
                    break outerProcess;
                }
            }
        }
    
    0000
    0001
    0010
    0011
    0100
    0101
    0110
    0111
    1000
    1001
    1010
    1011
    1100
    1101
    1110
    1111
    
    [A, W, L] [A, Y, L] [B, W, L] [B, Y, L] [C, W, L] [C, Y, L]
    [A, W, M] [A, Y, M] [B, W, M] [B, Y, M] [C, W, M] [C, Y, M]
    [A, W, K] [A, Y, K] [B, W, K] [B, Y, K] [C, W, K] [C, Y, K]
    [A, X, L] [A, Z, L] [B, X, L] [B, Z, L] [C, X, L] [C, Z, L]
    [A, X, M] [A, Z, M] [B, X, M] [B, Z, M] [C, X, M] [C, Z, M]
    [A, X, K] [A, Z, K] [B, X, K] [B, Z, K] [C, X, K] [C, Z, K]