Java 从多个列表生成所有组合
给定未知数量的列表,每个列表的长度未知,我需要生成一个包含所有可能的唯一组合的单数列表。 例如,给定以下列表:Java 从多个列表生成所有组合,java,list,algorithm,combinations,cartesian-product,Java,List,Algorithm,Combinations,Cartesian Product,给定未知数量的列表,每个列表的长度未知,我需要生成一个包含所有可能的唯一组合的单数列表。 例如,给定以下列表: X: [A, B, C] Y: [W, X, Y, Z] 那么我应该能够生成12个组合: [AW, AX, AY, AZ, BW, BX, BY, BZ, CW, CX, CY, CZ] 如果添加第三个包含3个元素的列表,我会有36个组合,以此类推 关于如何在Java中实现这一点,有什么想法吗? (伪代码也可以)使用其他答案提供的嵌套循环解决方案来组合两个列表 当您有两个以上的列
X: [A, B, C]
Y: [W, X, Y, Z]
那么我应该能够生成12个组合:
[AW, AX, AY, AZ, BW, BX, BY, BZ, CW, CX, CY, CZ]
如果添加第三个包含3个元素的列表,我会有36个组合,以此类推
关于如何在Java中实现这一点,有什么想法吗?(伪代码也可以)使用其他答案提供的嵌套循环解决方案来组合两个列表 当您有两个以上的列表时
列表中,这是一个列表列表。让result
成为所需排列的列表。您可以这样实现它:
void generatePermutations(List<List<Character>> lists, List<String> result, int depth, String current) {
if (depth == lists.size()) {
result.add(current);
return;
}
for (int i = 0; i < lists.get(depth).size(); i++) {
generatePermutations(lists, result, depth + 1, current + lists.get(depth).get(i));
}
}
generatePermutations(lists, result, 0, "");
没有递归唯一的组合:
[AW, AX, AY, AZ, BW, BX, BY, BZ, CW, CX, CY, CZ]
stringsarray[]=新字符串[]{“A”、“A”、“B”、“C”};
//将数组转换为列表
List list1=Arrays.asList(sArray);
List list2=Arrays.asList(sArray);
List list3=Arrays.asList(sArray);
LinkedList=新建LinkedList();
列表。添加(列表1);
列表。添加(列表2);
列表。添加(列表3);
集合组合=新树集合();
设置新的二进制文件;
for(字符串s:lists.removeFirst())
组合。添加(s);
而(!lists.isEmpty()){
List next=lists.removeFirst();
newCombinations=新树集();
用于(字符串s1:组合)
for(字符串s2:下一个)
newCombinations.add(s1+s2);
组合=新组合;
}
用于(字符串s:组合)
系统输出打印(s+“”);
这个话题很有用。我已经完全用Java重写了前面的解决方案,并且更加用户友好。此外,我使用集合和泛型以获得更大的灵活性:
/**
* Combines several collections of elements and create permutations of all of them, taking one element from each
* collection, and keeping the same order in resultant lists as the one in original list of collections.
*
* <ul>Example
* <li>Input = { {a,b,c} , {1,2,3,4} }</li>
* <li>Output = { {a,1} , {a,2} , {a,3} , {a,4} , {b,1} , {b,2} , {b,3} , {b,4} , {c,1} , {c,2} , {c,3} , {c,4} }</li>
* </ul>
*
* @param collections Original list of collections which elements have to be combined.
* @return Resultant collection of lists with all permutations of original list.
*/
public static <T> Collection<List<T>> permutations(List<Collection<T>> collections) {
if (collections == null || collections.isEmpty()) {
return Collections.emptyList();
} else {
Collection<List<T>> res = Lists.newLinkedList();
permutationsImpl(collections, res, 0, new LinkedList<T>());
return res;
}
}
/** Recursive implementation for {@link #permutations(List, Collection)} */
private static <T> void permutationsImpl(List<Collection<T>> ori, Collection<List<T>> res, int d, List<T> current) {
// if depth equals number of original collections, final reached, add and return
if (d == ori.size()) {
res.add(current);
return;
}
// iterate from current collection and copy 'current' element N times, one for each element
Collection<T> currentCollection = ori.get(d);
for (T element : currentCollection) {
List<T> copy = Lists.newLinkedList(current);
copy.add(element);
permutationsImpl(ori, res, d + 1, copy);
}
}
/**
*组合多个元素集合并创建所有元素的排列,从每个元素中提取一个元素
*集合,并在结果列表中保持与原始集合列表中相同的顺序。
*
*示例
*- Input={a,b,c},{1,2,3,4}
*- 输出={a,1},{a,2},{a,3},{a,4},{b,1},{b,3},{b,4},{c,1},{c,2},{c,3},{c,4}
*
*
*@param collections必须组合元素的集合的原始列表。
*@返回列表的结果集合以及原始列表的所有排列。
*/
公共静态集合排列(列表集合){
if(collections==null | | collections.isEmpty()){
返回集合。emptyList();
}否则{
Collection res=Lists.newLinkedList();
置换简单(集合,res,0,新LinkedList());
返回res;
}
}
/**{@link#置换(列表,集合)}的递归实现*/
私有静态void置换simple(列表ori、集合res、int d、列表current){
//如果深度等于原始集合数,则添加并返回最终集合
如果(d==ori.size()){
res.add(当前);
返回;
}
//从当前集合迭代并复制“当前”元素N次,每个元素一次
Collection currentCollection=ori.get(d);
对于(T元素:currentCollection){
列表副本=Lists.newLinkedList(当前);
复制。添加(元素);
置换单纯形(ori,res,d+1,copy);
}
}
我正在使用guava library创建集合。添加了一个基于迭代器的答案,以用于通用列表列表
,扩展了Ruslan Ostafiichuk答案的思想。我的想法是:
* List 1: [1 2]
* List 2: [4 5]
* List 3: [6 7]
*
* Take each element from list 1 and put each element
* in a separate list.
* combinations -> [ [1] [2] ]
*
* Set up something called newCombinations that will contains a list
* of list of integers
* Consider [1], then [2]
*
* Now, take the next list [4 5] and iterate over integers
* [1]
* add 4 -> [1 4]
* add to newCombinations -> [ [1 4] ]
* add 5 -> [1 5]
* add to newCombinations -> [ [1 4] [1 5] ]
*
* [2]
* add 4 -> [2 4]
* add to newCombinations -> [ [1 4] [1 5] [2 4] ]
* add 5 -> [2 5]
* add to newCombinations -> [ [1 4] [1 5] [2 4] [2 5] ]
*
* point combinations to newCombinations
* combinations now looks like -> [ [1 4] [1 5] [2 4] [2 5] ]
* Now, take the next list [6 7] and iterate over integers
* ....
* 6 will go into each of the lists
* [ [1 4 6] [1 5 6] [2 4 6] [2 5 6] ]
* 7 will go into each of the lists
* [ [1 4 6] [1 5 6] [2 4 6] [2 5 6] [1 4 7] [1 5 7] [2 4 7] [2 5 7]]
现在是代码。我使用集合
只是为了消除任何重复项。可替换为列表
。一切都应该天衣无缝地工作。:)
publicstaticset-getcombines(列表){
集合组合=新的HashSet();
设置新的二进制文件;
int指数=0;
//提取第一个列表中的每个整数
//并将其作为新列表添加到ints
for(ti:list.get(0)){
List newList=newarraylist();
新列表。添加(i);
组合。添加(新列表);
}
索引++;
while(索引
一块小试块
publicstaticvoidmain(字符串[]args){
列表l1=array.asList(1,2,3);
listl2=Arrays.asList(4,5);
listl3=Arrays.asList(6,7);
List lists=新建ArrayList();
列表。添加(l1);
添加(l2);
列表。添加(l3);
设置梳=获取组合(列表);
用于(列表:梳子){
System.out.println(list.toString());
}
}
- 无递归
- 命令
- 可以通过索引获得特定组合(无需构建所有其他排列):
类和main()
方法,最后:
public class TwoDimensionalCounter<T> {
private final List<List<T>> elements;
public TwoDimensionalCounter(List<List<T>> elements) {
this.elements = Collections.unmodifiableList(elements);
}
public List<T> get(int index) {
List<T> result = new ArrayList<>();
for(int i = elements.size() - 1; i >= 0; i--) {
List<T> counter = elements.get(i);
int counterSize = counter.size();
result.add(counter.get(index % counterSize));
index /= counterSize;
}
return result;//Collections.reverse() if you need the original order
}
public int size() {
int result = 1;
for(List<T> next: elements) result *= next.size();
return result;
}
public static void main(String[] args) {
TwoDimensionalCounter<Integer> counter = new TwoDimensionalCounter<>(
Arrays.asList(
Arrays.asList(1, 2, 3),
Arrays.asList(1, 2, 3),
Arrays.asList(1, 2, 3)
));
for(int i = 0; i < counter.size(); i++)
System.out.println(counter.get(i));
}
}
公共类二维计数器{
私人最终清单要素;
公共二维计数器(列表元素){
this.elements=Collections.unmodifiableList(元素);
}
公共列表获取(int索引){
列表结果=新建ArrayList();
对于(int i=elements.size()-1;i>=0;i--){
列表计数器=元素。获取(i);
int counterSize=counter.size();
result.add(counter.get(索引%counterSize));
索引/=副标题;
}
返回结果;//如果需要原始顺序,则返回Collections.reverse()
}
公共整数大小(){
int结果=1;
for(List next:elements)result*=next.size();
返回结果;
}
String[][] combinations = new String[][] {
new String[] { "0", "1" },
new String[] { "0", "1" },
new String[] { "0", "1" },
new String[] { "0", "1" } };
int[] indices = new int[combinations.length];
int currentIndex = indices.length - 1;
outerProcess: while (true) {
for (int i = 0; i < combinations.length; i++) {
System.out.print(combinations[i][indices[i]]);
}
System.out.println();
while (true) {
// Increase current index
indices[currentIndex]++;
// If index too big, set itself and everything right of it to 0 and move left
if (indices[currentIndex] >= combinations[currentIndex].length) {
for (int j = currentIndex; j < indices.length; j++) {
indices[j] = 0;
}
currentIndex--;
} else {
// If index is allowed, move as far right as possible and process next
// combination
while (currentIndex < indices.length - 1) {
currentIndex++;
}
break;
}
// If we cannot move left anymore, we're finished
if (currentIndex == -1) {
break outerProcess;
}
}
}
0000
0001
0010
0011
0100
0101
0110
0111
1000
1001
1010
1011
1100
1101
1110
1111
[A, W, L] [A, Y, L] [B, W, L] [B, Y, L] [C, W, L] [C, Y, L]
[A, W, M] [A, Y, M] [B, W, M] [B, Y, M] [C, W, M] [C, Y, M]
[A, W, K] [A, Y, K] [B, W, K] [B, Y, K] [C, W, K] [C, Y, K]
[A, X, L] [A, Z, L] [B, X, L] [B, Z, L] [C, X, L] [C, Z, L]
[A, X, M] [A, Z, M] [B, X, M] [B, Z, M] [C, X, M] [C, Z, M]
[A, X, K] [A, Z, K] [B, X, K] [B, Z, K] [C, X, K] [C, Z, K]