Получить список комбинаций элементов списков

Предположим, у меня есть 3 списка: ['q','w'], ['a','s'], ['z','x']. Как получить список возможных комбинаций из этих списков? Поэтому я получаю список [['q','a','z'],['q','s','z']] и тому подобное. Я сделал метод для двоих, но не могу изобразить один для N списков:

static <E> ArrayList combine(ArrayList<E> one,ArrayList<E> two)
{
    ArrayList<ArrayList<E>> combs=new ArrayList<ArrayList<E>>();
    for(E e:one)
    {
        for(E e2:two)
        {
            ArrayList ps=new ArrayList();
            ps.add(e);
            ps.add(e2);
            combs.add(ps);
        }
    }
    return combs;
}

Я узнал, что это сделано с помощью Sets.cartesianProduct компании Guava.

4 ответа

Решение

Вам нужно N вложенных циклов, что делает его сложным.

Вы можете добиться этого с помощью рекурсии, хотя.

static <E> ArrayList combine(ArrayList<E> soFar, ArrayList<E>... lists)
{
    // Rather than constantly making and remaking this list could just use one
    // and pass it around and add stuff to it. This works though.
    ArrayList<ArrayList<E>> combs=new ArrayList<ArrayList<E>>();

    // Loop through the first list looking for elements
    for(E e:lists[0])
    {
       // Create a new List to build this combination
       ArrayList<E> temp = new ArrayList<>(soFar);
       // Add this element to the combination
       temp.add(e);
       // If there are more lists recurse down
       if (lists.length > 1) {
           // Use recursion to add all combinations of the remaining lists
           combs.addAll(combine(temp, lists.subList(1)));
       } else {
           // There are no more lists so we are done, add temp to the combos
           combs.add(temp);
       }
    }
    return combs;
}


// Call this method to start things going, the other one should probably be private
static <E> ArrayList combine(ArrayList<E>... lists)
    return combine(new ArrayList<E>(), lists);
}

Для ленивых (использующих гуаву):

Set<List<String>> result = Sets.cartesianProduct(
                ImmutableSet.of("q", "w"),
                ImmutableSet.of("a", "s"),
                ImmutableSet.of("z", "x")
        );

System.out.println(result);

выход:

[ [q, a, z], [q, a, x], [q, s, z], [q, s, x], [w, a, z], [w, a, x], [w, s, z], [w, s, x] ]

Возможно, вы захотите взглянуть на класс https://github.com/javagl/Combinatorics/blob/master/src/main/java/de/javagl/utils/math/combinatorics/MixedRangeCombinationIterable.java ("автономный"). класс, просто скопируйте и вставьте в свой проект)

Пример использования:

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class Combinations
{
    public static void main(String[] args)
    {
        List<List<Character>> lists = new ArrayList<List<Character>>();
        lists.add(Arrays.asList('q','w'));
        lists.add(Arrays.asList('a','s'));
        lists.add(Arrays.asList('z','x'));

        MixedRangeCombinationIterable<Character> iterable = 
            new MixedRangeCombinationIterable<Character>(lists);
        for (List<Character> element : iterable)
        {
            System.out.println(element);
        }
    }
}

Вы фактически вычисляете элементы входных наборов http://en.wikipedia.org/wiki/Cartesian_product

Вверх вы можете создать внутренний класс с помощью конструктора (параметры...), так что вы можете поместить список этого класса, который обрабатывает все комбинации

Другие вопросы по тегам