根据键

时间:2015-08-28 21:04:19

标签: java arrays merge hashmap maps

我因为这个奇怪的问题而被困2小时(我很蠢)。

我的地图中包含<String,Set>

等值
  • A = 1,2,3
  • B = 4,5
  • C = 6

我正在寻找的输出是

  • A = 1和B = 4和C = 6
  • A = 1和B = 5和C = 6
  • A = 2及B = 4和C = 6
  • A = 2及B = 5和C = 6
  • A = 3和B = 4和C = 6
  • A = 3和B = 5和C = 6

到目前为止我做了什么: -

  • 根据第一个键迭代地图并在数组中存储值
  • 迭代第二个键,但我不确定如何将第一个结果中的值合并到此结果中。
  • 忘记第三个及后续的密钥。

这可能听起来像一个非常愚蠢的问题,但我无法弄清楚这一点。我试图避免这种情况到达这里,但我无法改变!!

请帮忙。

注意: - 我也使用了multiset,但它接受了值的重复值,因此必须使用set.Hence最终得到map<String,Set>

2 个答案:

答案 0 :(得分:4)

以下代码可以处理任何大小的Map,除了空,以及每个Set的任何大小,除了空。空Map / Set会抛出错误。

当然,一旦定义了预期的输出,扩展代码以处理 empty 应该相当简单。

Map<String, Set<String>> map = new LinkedHashMap<>();
map.put("A", new LinkedHashSet<>(Arrays.asList("1", "2", "3")));
map.put("B", new LinkedHashSet<>(Arrays.asList("4", "5")));
map.put("C", new LinkedHashSet<>(Arrays.asList("6")));

List<String> result = null;
for (Map.Entry<String, Set<String>> entry : map.entrySet()) {
    String key = (result == null ? "" : "&") + entry.getKey() + "=";
    Set<String> values = entry.getValue();
    if (values.isEmpty())
        throw new IllegalArgumentException("Empty set not supported");
    List<String> crossJoin = new ArrayList<>((result == null ? 1 : result.size()) * values.size());
    if (result == null)
        for (String value : values)
            crossJoin.add(key + value);
    else
        for (String left : result)
            for (String value : values)
                crossJoin.add(left + key + value);
    result = crossJoin;
}
if (result == null)
    throw new IllegalArgumentException("Empty map not supported");
for (String value : result)
    System.out.println(value);

输出

A=1&B=4&C=6
A=1&B=5&C=6
A=2&B=4&C=6
A=2&B=5&C=6
A=3&B=4&C=6
A=3&B=5&C=6

答案 1 :(得分:1)

这里有一个更容易阅读的答案,如果您的代码暂时停留一段时间并且您可能想要更改格式或处理空案例,那么这些答案将更易于维护。它自然地处理具有空映射和没有允许值集的键的情况。

我认为订单对您来说并不重要,但您可以用列表替换这些集合以获得更可预测/一致的订单。

/**
 * A nested pair class to handle the mappings like A:1.
 */
private static class Pair{
    public Pair(String k,String v){
        this.k = k;
        this.v = v;
    }

    String k;
    String v;

    public String toString(){
        return k+"="+v;
    }
}

/**
 * Given a set like 
 * {{A:"s1",B:"s4","C:s5"}
 * {A:"s1",B:"s4","C:s6"}
 * {A:"s2",B:"s4","C:s5"}
 * {A:"s2",B:"s4","C:s6"}
 * {A:"s3",B:"s4","C:s5"}
 * {A:"s3",B:"s4","C:s6"}}
 * 
 * Converts the contents to string like:
 * A=s1&B=s4&C=s5
 * A=s1&B=s4&C=s6
 * A=s2&B=s4&C=s5
 * A=s2&B=s4&C=s6
 * A=s3&B=s4&C=s5
 * A=s3&B=s4&C=s6
 * @param pairCombinations
 * @return
 */
public static String format(Set<Set<Pair>> pairCombinations){
    String result = "";
    for(Set<Pair> pairSet : pairCombinations){
        result += formatPairSet(pairSet)+"\n";
    }

    return result;
}

private static String formatPairSet(Set<Pair> pairSet) {
    String result = "";
    boolean isFirst = true;
    for(Pair pair : pairSet){
        result+= (isFirst? "" : "&");
        result += pair.k+"="+pair.v;
        isFirst = false;
    }
    return result;
}

/**
 * Given a map of the form:
 * A:{"s1","s2","s3"}
 * B:{"s4"}
 * C:{"s5","s6"}
 * 
 * Will return all possible combinations of pairs in 
 * the map as:
 * {{A:"s1",B:"s4","C:s5"}
 * {A:"s1",B:"s4","C:s6"}
 * {A:"s2",B:"s4","C:s5"}
 * {A:"s2",B:"s4","C:s6"}
 * {A:"s3",B:"s4","C:s5"}
 * {A:"s3",B:"s4","C:s6"}}
 * @param map
 * @return
 */
public static Set<Set<Pair>> getCombinations(Map<String,Set<String>> map){

    Set<Set<Pair>> combinations = new HashSet<Set<Pair>>();
    if(map.entrySet().isEmpty()){
        return combinations;
    }
    combinations.add(new HashSet<Pair>());

    Set<Pair> pairsForKey = null;
    for(Entry<String,Set<String>> mapEntry : map.entrySet()){
        //Ex: {C:"s5",C:"s6"}
        pairsForKey = getPairs(mapEntry);

        //Ex: {{A:s1,B:s4},{A:s2,B:s4},{A:s3,B:s4}}
        combinations = join(combinations,pairsForKey);
    }

    return combinations;
}

private static Set<Pair> getPairs(Entry<String, Set<String>> kWithValidVs) {
    Set<Pair> pairs = new HashSet<Pair>();
    for(String v : kWithValidVs.getValue()){
        pairs.add(new Pair(kWithValidVs.getKey(),v));
    }
    return pairs;
}

/**
 * Given a set of combinations like:
 * {{A:s1,B:s4},{A:s2,B:s4},{A:s3,B:s4}} and a set to join with it like {C:s5,C:s6},
 * will join the set to the existing combinations like:
 * {{A:s1,B:s4,C:s5},{A:s2,B:s4,C:s5},{A:s3,B:s4,C:s5},{A:s1,B:s4,C:s6},{A:s2,B:s4,A:s6},{A:s3,B:s4,C:s6}}
 * @param combinations
 * @param set
 * @return
 */
private static Set<Set<Pair>> join(Set<Set<Pair>> combinations,
        Set<Pair> set) {
    Set<Set<Pair>> join = new HashSet<Set<Pair>>();

    //comment this 'if' if you want keys with empty lists to eliminate all combos.
    if(set.isEmpty()){
        return combinations;
    }

    for(Set<Pair> combo : combinations){
        for(Pair pair : set){
            Set<Pair> newCombo = new HashSet<Pair>();
            newCombo.addAll(combo);
            newCombo.add(pair);
            join.add(newCombo);
        }
    }
    return join;
}

public static void main(String[] args){
    Map<String,Set<String>> map = new HashMap<String,Set<String>>();
    Set<String> aVals = new HashSet<String>();
    aVals.add("1");
    aVals.add("2");
    aVals.add("3");

    Set<String> bVals = new HashSet<String>();
    bVals.add("4");

    Set<String> cVals = new HashSet<String>();
    cVals.add("5");
    cVals.add("6");

    map.put("A", aVals);
    map.put("B", bVals);
    map.put("C", cVals);

    Set<Set<Pair>> combinations =getCombinations(map);
    String printableResult = format(combinations);
    System.out.print(printableResult);
}

输出:

A=2&B=4&C=6
A=2&B=4&C=5
A=1&B=4&C=6
B=4&C=5&A=3
B=4&A=3&C=6
A=1&B=4&C=5