我很努力地生成属性列表的所有可能值组合。例如,对于具有以下值的三个属性A,B,C:A的{a1,a2},B的{b1,b2}和C的{c1,c2},我应该得到8种组合: / p>
a1,b1,c1
a1,b1,c2
a1,b2,c1
a1,b2,c2
a2,b1,c1
a2,b1,c2
a2,b2,c1
a2,b2,c2
我使用了以下两个递归Java函数,其中attribute_to_domain
是Map
,在其中我们将每个属性都设为key
,并将其值都设为value
,然后添加每个组合作为<ArrayList<String>
到enumerate_tuples
作为ArrayList<ArrayList<String>>
public void fillTuples(Map<String, Set<String>> attribute_to_domain, ArrayList<String> attributes, ArrayList<ArrayList<String>> enumerate_tuples)
{
for (Map.Entry<String, Set<String>> entrySet :attribute_to_domain.entrySet()) {
String attribute=entrySet.getKey();
attributes.add(attribute);
}
int pos = 0;
Set<String> domain = attribute_to_domain.get(attributes.get(pos));
for (Iterator<String> it = domain.iterator(); it.hasNext();) {
String val = it.next();
ArrayList<String> tuple=new ArrayList<String>();
tuple.add(val);
fillTuples(attribute_to_domain, attributes, 1, tuple, enumerate_tuples);
tuple.remove(tuple.size()-1);
assert(tuple.isEmpty());
}
}
public void fillTuples(Map<String, Set<String>> attribute_to_domain, ArrayList<String> attributes, int pos, ArrayList<String> tuple, ArrayList<ArrayList<String>> enumerate_tuples)
{
assert(tuple.size() == pos);
if (pos == attributes.size())
{
enumerate_tuples.add(tuple);
return;
}
Set<String> domain = attribute_to_domain.get(attributes.get(pos));
for (Iterator<String> it = domain.iterator(); it.hasNext();) {
String val = it.next();
tuple.add(val);
fillTuples(attribute_to_domain, attributes, pos+1, tuple, enumerate_tuples);
tuple.remove(tuple.size()-1);
}
}
我得到enumerate_tuples
带有空元素的问题,我无法通过调用保留发生在其上的更改。
请问如何解决这个问题?预先感谢。
答案 0 :(得分:1)
有一种更简单,更快速的解决方案,不需要递归。
可以高级地计算输出组合的数量:在您的情况2*2*2
中属性的相乘,但是每种组合都适用。
此外,我们可以基于组合索引来计算将在每个组合中放置哪个值。如果我们假设组合索引从0到7:
为A
:
-组合0-3将包含a1
-组合4-7将包含a2
为B
-组合0、1、4、5将包含b1
-组合2、3、6、7将包含b2
为C
-组合0、2、4、6将包含c1
-组合1,3,5,7将包含c2
因此,值放置的公式基于组合索引,属性的顺序(首先为A
等)和属性中值的顺序。
该算法的复杂度为o(n * m),其中n是属性数,m是值。
答案 1 :(得分:0)
修订自Cartesian product of arbitrary sets in Java
import java.util.Arrays;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
public class CartesianProduct {
public static Set<Set<Object> > cartesianProduct(Set<?>... sets) {
if (sets.length < 2)
throw new IllegalArgumentException(
"Can't have a product of fewer than two sets (got " +
sets.length + ")");
return _cartesianProduct(0, sets);
}
private static Set<Set<Object> > _cartesianProduct(int index, Set<?>... sets) {
Set<Set<Object> > ret = new TreeSet<Set<Object> >(new Comparator<Set<Object> >() {
@Override
public int compare(Set<Object> o1, Set<Object> o2) {
return o1.toString().compareTo(o2.toString());
}
});
if (index == sets.length) {
ret.add(new TreeSet<Object>());
} else {
for (Object obj : sets[index]) {
for (Set<Object> set : _cartesianProduct(index+1, sets)) {
set.add(obj);
ret.add(set);
}
}
}
return ret;
}
public static void main(String[] args) {
Map<String, Set<String> > dataMap = new HashMap<String, Set<String> >();
dataMap.put("A", new TreeSet<String>(Arrays.asList("a1", "a2")));
dataMap.put("B", new TreeSet<String>(Arrays.asList("b1", "b2")));
dataMap.put("C", new TreeSet<String>(Arrays.asList("c1", "c2")));
System.out.println(cartesianProduct(dataMap.values().toArray(new Set<?>[0])));
}
}