如何用Java生成笛卡尔积?

时间:2011-11-10 16:13:56

标签: java cartesian-product

我有一些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,

任何人都可以帮助我吗?

6 个答案:

答案 0 :(得分:5)

使用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());

答案 1 :(得分:4)

使用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 (")");
    }
}

答案 2 :(得分:1)

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

    中间输出:

    [[a], [b], [c]]
    [[d], [e]]
    [[f]]
    
  • reduce 方法将成对的二维列表相加为一个二维列表。

    最终输出:

    [[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

答案 3 :(得分:0)

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

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

答案 4 :(得分:0)

使用番石榴...这是列表本身的笛卡尔积的示例:

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()) + "");
    }
}

答案 5 :(得分:0)

多个列表的笛卡尔积

您可以使用带有三个参数的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