【问题标题】:Combinations of attributes values属性值的组合
【发布时间】:2018-10-15 06:42:27
【问题描述】:

我很难生成属性列表的所有可能的值组合。例如,对于具有以下值的三个属性 A、B、C:A 的 {a1,a2}、B 的 {b1,b2} 和 C 的 {c1,c2},我应该得到 8 个组合:

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_domainMap,我们将每个属性作为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 带有空元素,我无法保留通过调用对其进行的更改。

请问我该如何解决这个问题?提前致谢。

【问题讨论】:

  • a1 b1 c1 怎么样?
  • 为什么是奇怪的方法名称?这个约定是从哪里来的?
  • 请阅读 java 命名约定。你到处都在违反它们,这使得你的代码对于习惯阅读 java 代码的人来说真的很难阅读。并且:阅读有关在 Java 中使用 assert() 的优点(和许多缺点)。大多数时候,这确实是个坏主意。然后我想知道为什么要使用 Iterators 来迭代简单的集合。您的代码与惯用的 Java 完全相反...
  • 其实我是把代码从C++转成Java的,所以我认为问题出在C++中通过引用和Java中的值传递参数。

标签: java recursion arraylist hashmap


【解决方案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 first 等)和属性中值的顺序。

该算法的复杂度为 o(n*m),其中 n 是属性数,m 是值数。

【讨论】:

  • 感谢您的回答,但我需要一个通用的编码解决方案。
  • 这是“编码的通用解决方案”。你的意思是你需要有人为你编码吗?
【解决方案2】:

修改自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])));
    }

}

【讨论】:

  • 感谢您的回答。我已经尝试过了,但是在长返回语句中出现错误,其中许多符号无法找到,例如 e1、e2 流、toList 和 orElse。如果您能更正我的代码,我们将不胜感激。再次感谢。
  • 非常感谢。您能否推荐我如何将集合从预定义的“dataMap”传递到大小未知的“cartesianProduct”。
  • 请看更新后的答案:cartesianProduct(dataMap.values().toArray(new Set>[0]))
猜你喜欢
  • 2017-11-30
  • 2011-12-15
  • 2018-08-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-02-20
  • 2019-06-11
  • 1970-01-01
相关资源
最近更新 更多