用Java查找笛卡尔积

时间:2011-07-03 14:51:59

标签: java math cartesian-product

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

example 1 :
sets :(ab) (bc) (ca)

笛卡尔积,

  

abc aba acc aca bbc bba bcc bca

example 2 :
sets : (zyx) b c

笛卡尔积,

  

zbc ybc xbc

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

4 个答案:

答案 0 :(得分:6)

您可以使用Sets.cartesianProduct() method中的Google's Guava libraries生成笛卡儿积品:

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

如果只有一切都那么容易!

答案 1 :(得分: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)

答案 2 :(得分:0)

this paper(a "functional pearl")中可以找到一种纯粹的功能方法......但它可能不容易转换为Java。

答案 3 :(得分:0)

注意: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