【问题标题】:How do I generate a Cartesian product in Java?如何在 Java 中生成笛卡尔积?
【发布时间】:2011-12-26 07:47:22
【问题描述】:

我有多个ArrayList,每个ArrayList 都有对象,每个对象都可以有不同的长度。我需要像下面的例子一样生成排列:

假设我有 2 个ArrayList:

ArrayList A 有对象a、对象b 和对象c
ArrayList B 有对象d,对象e

那么输出应该是 6 个新的ArrayList 与这些组合:

组合1对象a和对象d,
组合2对象a和对象e,
组合3对象b和对象d,
组合4对象b和对象e,
组合5对象c和对象d,
组合6对象c和对象e

谁能帮帮我?

【问题讨论】:

    标签: java list arraylist cartesian-product


    【解决方案1】:

    番石榴 19+

    Lists.cartesianProduct(List...)
    

    例如

    List<Object> list1 = Arrays.asList("a", "b", "c");
    List<Object> list2 = Arrays.asList("d", "e");
    System.out.println(Lists.cartesianProduct(list1, list2));
    

    输出

    [[a, d], [a, e], [b, d], [b, e], [c, d], [c, e]]
    

    【讨论】:

      【解决方案2】:

      Java8

      List<String> a = Arrays.asList("a", "b", "c");
      List<String> b = Arrays.asList("d", "e");
      String[][] AB = a.stream()
              .flatMap(ai -> b.stream()
                      .map(bi -> new String[]{ai, bi}))
              .toArray(String[][]::new);
      System.out.println(Arrays.deepToString(AB));
      

      输出

      [[a, d], [a, e], [b, d], [b, e], [c, d], [c, e]]
      

      获取List

      List<List<String>> ll = a.stream()
              .flatMap(ai -> b.stream()
                      .map(bi -> new ArrayList<>(Arrays.asList(ai, bi))))
              .collect(Collectors.toList());
      

      【讨论】:

        【解决方案3】:

        使用 Iterable+Iterator:

        import java.util.*;
        
        class CartesianIterator <T> implements Iterator <List <T>> {
        
            private final List <List <T>> lilio;    
            private int current = 0;
            private final long last;
        
            public CartesianIterator (final List <List <T>> llo) {
                lilio = llo;
                long product = 1L;
                for (List <T> lio: lilio)
                    product *= lio.size ();
                last = product;
            } 
        
            public boolean hasNext () {
                return current != last;
            }
        
            public List <T> next () {
                ++current;
                return get (current - 1, lilio);
            }
        
            public void remove () {
                ++current;
            }
        
            private List<T> get (final int n, final List <List <T>> lili) {
                switch (lili.size ())
                {
                    case 0: return new ArrayList <T> (); // no break past return;
                    default: {
                        List <T> inner = lili.get (0);
                        List <T> lo = new ArrayList <T> ();
                        lo.add (inner.get (n % inner.size ()));
                        lo.addAll (get (n / inner.size (), lili.subList (1, lili.size ())));
                        return lo;
                    }
                }
            }
        }
        
        class CartesianIterable <T> implements Iterable <List <T>> {
        
            private List <List <T>> lilio;  
        
            public CartesianIterable (List <List <T>> llo) {
                lilio = llo;
            }
        
            public Iterator <List <T>> iterator () {
                return new CartesianIterator <T> (lilio);
            }
        }
        

        您可以在简化的 for 循环中使用它们:

        class CartesianIteratorTest {
        
            public static void main (String[] args) {
                List <Character> la = Arrays.asList (new Character [] {'a', 'b', 'c'});
                List <Character> lb = Arrays.asList (new Character [] {'d', 'e'});      
                List <List <Character>> llc = new ArrayList <List <Character>> ();
                llc.add (la);
                llc.add (lb);
        
                CartesianIterable <Character> ci = new CartesianIterable <Character> (llc);
                for (List<Character> lo: ci)
                    show (lo);
            }
        
            public static void show (List <Character> lo) {
                System.out.print ("(");
                for (Object o: lo)
                    System.out.print (o);
                System.out.println (")");
            }
        }
        

        【讨论】:

          【解决方案4】:

          使用嵌套的 for 循环,每个 ArrayList 都有一个循环,如下所示。我假设我有两个 ArrayLists - intList 和 stringList。我可以有两个嵌套的 for 循环(每个列表一个)来生成排列。

          for (Integer i : intList) {
              for (String s : stringList) {
                  ...
              }
          }
          

          【讨论】:

            【解决方案5】:

            使用 map 和 reduce 方法的多个列表的笛卡尔积 H3>
            • map 方法将列表中的每个元素表示为一个单例列表,并指定结果的格式。

              中间输出:

              [[a], [b], [c]]
              [[d], [e]]
              [[f]]
              
            • reduce 方法将 2D 列表对汇总为单个 2D 列表。

              最终输出:

              [[a, d, f], [a, e, f], [b, d, f], [b, e, f], [c, d, f], [c, e, f]]
              

            Try it online!

            public static void main(String[] args) {
                List<String> a = Arrays.asList("a", "b", "c");
                List<String> b = Arrays.asList("d", "e");
                List<String> c = Arrays.asList("f");
            
                List<List<String>> cp = cartesianProduct(Arrays.asList(a, b, c));
                // output
                System.out.println(cp);
            }
            
            public static <T> List<List<T>> cartesianProduct(List<List<T>> lists) {
                // check if not null
                if (lists == null) return null;
                // cartesian product of multiple lists
                return lists.stream()
                        // only those lists that are not null and not empty
                        .filter(list -> list != null && list.size() > 0)
                        // represent each list element as a singleton list
                        .map(list -> list.stream().map(Collections::singletonList)
                                // Stream<List<List<T>>>
                                .collect(Collectors.toList()))
                        // intermediate output
                        .peek(System.out::println)
                        // stream of lists into a single list
                        .reduce((lst1, lst2) -> lst1.stream()
                                // combinations of inner lists
                                .flatMap(inner1 -> lst2.stream()
                                        // concatenate into a single list
                                        .map(inner2 -> Stream.of(inner1, inner2)
                                                .flatMap(List::stream)
                                                .collect(Collectors.toList())))
                                // list of combinations
                                .collect(Collectors.toList()))
                        // otherwise an empty list
                        .orElse(Collections.emptyList());
            }
            

            另见:Cartesian product of an arbitrary number of sets

            【讨论】:

              【解决方案6】:

              使用番石榴...这是一个列表与自身的笛卡尔积的示例:

              public static void main(String[] args) {
                //How to do a cartesian product of a List of items
                List<Integer> listToSelfMultiply = Arrays.asList(
                    new Integer(1), new Integer(2), new Integer(3), new Integer(4));
                LinkedList<Integer> linkedListCopy = Lists.newLinkedList(listToSelfMultiply);
                for (Integer i : listToSelfMultiply) {
                  if (linkedListCopy.size() == 1) {
                    break;
                  }
                  linkedListCopy.remove();
                  System.out.println("" + Arrays.deepToString(
                      Lists.cartesianProduct(Arrays.asList(i), linkedListCopy).toArray()) + "");
                  }
              }
              

              【讨论】:

                【解决方案7】:

                多个列表的笛卡尔积

                您可以使用带有三个参数的reduce方法:

                • identity - 指定结果存根。

                  List<List<T>>
                  
                • accumulator - 将列表元素附加到结果中。

                  List<List<T>> result, List<T> list
                  
                • combiner - 用于并行模式,合并结果。

                  List<List<T>> result1, List<List<T>> result2
                  

                Try it online!

                /**
                 * @param lists the lists for multiplication
                 * @param <T>   the type of list element
                 * @return the Cartesian product
                 */
                public static <T> List<List<T>> cartesianProduct(List<List<T>> lists) {
                    // check if incoming data is not null
                    if (lists == null) return Collections.emptyList();
                    return lists.stream()
                        // non-null and non-empty lists
                        .filter(list -> list != null && list.size() > 0)
                        // stream of lists into a single list
                        .reduce(// identity - specify the result stub
                                Collections.singletonList(Collections.emptyList()),
                                // accumulator - append elements of lists to the result
                                (result, list) -> result.stream()
                                        .flatMap(inner -> list.stream()
                                                .map(el -> {
                                                    List<T> nList = new ArrayList<>(inner);
                                                    nList.add(el);
                                                    return nList;
                                                }))
                                        // list of combinations
                                        .collect(Collectors.toList()),
                                // combiner - is used in parallel mode, combines the results
                                (result1, result2) -> {
                                    result1.addAll(result2);
                                    return result1;
                                });
                }
                
                public static void main(String[] args) {
                    List<String> l1 = Arrays.asList("A", "B");
                    List<String> l2 = Arrays.asList("C", "D");
                    List<String> l3 = Arrays.asList("E", "F");
                
                    List<List<String>> cp = cartesianProduct(Arrays.asList(l1, l2, l3));
                    // output
                    System.out.println(cp);
                }
                

                输出:

                [[A,C,E],[A,C,F],[A,D,E],[A,D,F],[B,C,E],[B,C,F],[B,D,E],[B,D,F]]
                

                另见:Cartesian product of 3 collections

                【讨论】:

                  猜你喜欢
                  • 1970-01-01
                  • 2016-10-08
                  • 2021-05-06
                  • 2016-05-07
                  • 2021-09-05
                  • 2015-11-08
                  • 1970-01-01
                  • 2013-12-25
                  • 2012-11-18
                  相关资源
                  最近更新 更多