【问题标题】:Finding cartesian product in Java在 Java 中查找笛卡尔积
【发布时间】:2011-07-03 14:51:58
【问题描述】:

我想找到一组元素的笛卡尔积。这是一个例子

示例 1:

sets : (ab) (bc) (ca)

笛卡尔积是:

abc aba acc aca bbc bba bcc bca

示例 2:

sets : (zyx) b c

笛卡尔积是:

zbc ybc xbc

所以我正在考虑一种在 Java 中执行的算法,它可以在开始时找到在编译时定义的特定数量组的笛卡尔积。

【问题讨论】:

    标签: java math set cartesian-product


    【解决方案1】:

    您可以使用Google's Guava libraries 中的Sets.cartesianProduct() 方法生成笛卡尔积:

    com.google.common.collect.Sets.cartesianProduct(Set[] yourSets)
    

    要是一切都这么简单就好了!

    【讨论】:

      【解决方案2】:

      定义你自己的Iterator/Iterable:

      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);
          }
      }
      

      并使用您的数据进行测试:

      class CartesianIteratorTest {
      
          public static void main (String[] args) {
              List <Character> la = Arrays.asList (new Character [] {'a', 'b'});
              List <Character> lb = Arrays.asList (new Character [] {'b', 'c'});      
              List <Character> lc = Arrays.asList (new Character [] {'c', 'a'});
              List <List <Character>> llc = new ArrayList <List <Character>> ();
              llc.add (la);
              llc.add (lb);
              llc.add (lc);
      
              CartesianIterable <Character> ci = new CartesianIterable <Character> (llc);
              for (List<Character> lo: ci)
                  show (lo);
      
              la = Arrays.asList (new Character [] {'x', 'y', 'z'});
              lb = Arrays.asList (new Character [] {'b'});    
              lc = Arrays.asList (new Character [] {'c'});
              llc = new ArrayList <List <Character>> ();
              llc.add (la);
              llc.add (lb);
              llc.add (lc);
      
              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 (")");
          }
      }
      

      结果:

      (abc)
      (bbc)
      (acc)
      (bcc)
      (aba)
      (bba)
      (aca)
      (bca)
      (xbc)
      (ybc)
      (zbc)
      

      【讨论】:

        【解决方案3】:

        注意:Set不包含重复元素的集合。如果您在不同的集合中有重复的元素,那么笛卡尔积中的每个集合将只包含其中一个。

        您可以创建一个通用方法来获取笛卡尔积并指定要存储它的集合类型。例如,SetList

        使用map和reduce方法的笛卡尔积

        • map 方法将集合的每个元素表示为单例集合,并指定结果的格式。

        • reduce 方法将 2D 集合对汇总为单个 2D 集合。

        Try it online!

        public static void main(String[] args) {
            List<Set<String>> sets = List.of(
                    Set.of("A", "B"), Set.of("B", "C"), Set.of("C", "A"));
        
            List<Set<String>> cpSet = cartesianProduct(HashSet::new, sets);
            List<List<String>> cpList = cartesianProduct(ArrayList::new, sets);
        
            // output, order may vary
            System.out.println(toString(cpSet));
            //ABC, AB, AC, AC, BC, BA, BC, BCA
            System.out.println(toString(cpList));
            //ABC, ABA, ACC, ACA, BBC, BBA, BCC, BCA
        }
        
        /**
         * @param cols the input collection of collections
         * @param nCol the supplier of the output collection
         * @param <E>  the type of the element of the collection
         * @param <R>  the type of the return collections
         * @return List<R> the cartesian product of the multiple collections
         */
        public static <E, R extends Collection<E>> List<R> cartesianProduct(
                Supplier<R> nCol, Collection<? extends Collection<E>> cols) {
            // check if the input parameters are not null
            if (nCol == null || cols == null) return null;
            return cols.stream()
                // non-null and non-empty collections
                .filter(col -> col != null && col.size() > 0)
                // represent each element of a collection as a singleton collection
                .map(col -> col.stream()
                    .map(e -> Stream.of(e).collect(Collectors.toCollection(nCol)))
                    // Stream<List<R>>
                    .collect(Collectors.toList()))
                // summation of pairs of inner collections
                .reduce((col1, col2) -> col1.stream()
                    // combinations of inner collections
                    .flatMap(inner1 -> col2.stream()
                        // concatenate into a single collection
                        .map(inner2 -> Stream.of(inner1, inner2)
                            .flatMap(Collection::stream)
                            .collect(Collectors.toCollection(nCol))))
                    // list of combinations
                    .collect(Collectors.toList()))
                // otherwise an empty list
                .orElse(Collections.emptyList());
        }
        
        // supplementary method, returns a formatted string
        static <E extends String> String toString(List<? extends Collection<E>> cols) {
            return cols.stream().map(col -> String.join("", col))
                    .collect(Collectors.joining(", "));
        }
        

        另见:Cartesian product of an arbitrary number of sets

        【讨论】:

          猜你喜欢
          • 2013-12-25
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-12-26
          • 1970-01-01
          相关资源
          最近更新 更多