递归或迭代地从 HashMap 中检索键值组合

Posted

技术标签:

【中文标题】递归或迭代地从 HashMap 中检索键值组合【英文标题】:Recursively or iteratively retrieve key-value combinations from a HashMap 【发布时间】:2011-07-16 10:17:23 【问题描述】:

我想从HashMap 中检索k,v-pairs。 条目是这样的:

a = 3,4
b = 5,6

等等。我需要这些值的组合。

a=3, b=5
a=3, b=6
a=4, b=5
a=4, b=6

我不知道值有多少个键和多少个条目。使用entrySet 我可以获得值但不能获得组合。它看起来像递归,但如何?

这是我的代码:

HashMap<String, String[]> map = new HashMap<String, String[]>();

BufferedReader file = new BufferedReader(new FileReader("test.txt"));
String str;

while ((str = file.readLine()) != null) 
    
    // ... logic
    
    map.put(key, value);


System.out.println("number of keys: " + map.size());
for (Map.Entry<String, String[]> entry : map.entrySet()) 
    for (String value : entry.getValue()) 
        System.out.println(entry.getKey() + ": " + value);
    

file.close();

【问题讨论】:

我不清楚:“a”是您的键,“3”(来自 a 的列表)是您的值,还是“3”是 a 的键和“5”是 b 的值? a 是键,3 和 4 是字符串。因此“字符串 []”。值为 String[] 【参考方案1】:

你可以试试下面的代码:

public void mapPermute(Map<String, String[]> map, String currentPermutation) 
    String key = map.keySet().iterator().next(); // get the topmost key

    // base case
    if (map.size() == 1)           
        for (String value : map.get(key)) 
            System.out.println(currentPermutation + key + "=" + value);
        
     else 
        // recursive case
        Map<String, String[]> subMap = new HashMap<String, String[]>(map);

        for (String value : subMap.remove(key)) 
            mapPermute(subMap, currentPermutation + key + "=" + value + ", ");
        
    

不保证内存效率或速度。如果要保留映射中键的顺序,则必须传入 TreeMap 并更改代码以在递归情况下使用 TreeMap

正如基本情况所暗示的,我假设您的地图中至少有一个条目。

【讨论】:

【参考方案2】:

您可以使用 map 和 reduce 方法获得地图键值组合的 笛卡尔积

Try it online!

Map<String, String[]> map = Map.of(
        "a", new String[]"3", "4",
        "b", new String[]"5", "6");
List<Map<String, String>> comb = map.entrySet().stream()
        // Stream<List<Map<String,String>>>
        .map(e -> Arrays.stream(e.getValue())
                .map(v -> Map.of(e.getKey(), v))
                .collect(Collectors.toList()))
        // summation of pairs of list into a single list
        .reduce((list1, list2) -> list1.stream()
                // combinations of inner maps
                .flatMap(map1 -> list2.stream()
                        // concatenate into a single map
                        .map(map2 -> 
                            Map<String, String> m = new HashMap<>();
                            m.putAll(map1);
                            m.putAll(map2);
                            return m;
                        ))
                // list of combinations
                .collect(Collectors.toList()))
        // otherwise, an empty list
        .orElse(Collections.emptyList());
// output, order may vary
comb.forEach(System.out::println);

输出,顺序可能不同:

a=3, b=5
a=3, b=6
a=4, b=5
a=4, b=6

另见:Cartesian product of map values

【讨论】:

【参考方案3】:

在我看来你真的想要MultiMap。特别是,ArrayListMultimap 允许重复条目:

ArrayListMultimap<String, String> map = ArrayListMultimap.create();

for each line in file:
    parse key k
    for each value in line:
        parse value v
        map.put(k, v);

for (Map.Entry<String, String> entry : map.entries()) 
    String key = entry.getKey();
    String value = entry.getValue();


如果您想要地图的笛卡尔积,您可以直接使用递归计算,或者您可以迭代地图:创建一个迭代器列表并迭代里程表样式;当迭代器 N 到达终点时,推进迭代器 N+1 并重置迭代器 1..N。


随便找了找this SO question。

因此,我建议您使用 guava 的 Sets.cartesianProduct 作为笛卡尔积。这是我的代码,你可以适应你的输入逻辑:

String key1 = "a";
Set<Integer> values1 = Sets.newLinkedHashSet(Arrays.asList(1, 2, 3, 4));
String key2 = "b";
Set<Integer> values2 = Sets.newLinkedHashSet(Arrays.asList(5, 6, 7));
String key3 = "c";
Set<Integer> values3 = Sets.newLinkedHashSet(Arrays.asList(8, 9));

List<String> keys = Arrays.asList(key1, key2, key3);
Set<List<Integer>> product = Sets.cartesianProduct(values1, values2, values3);
for (List<Integer> values : product) 
    for (int i = 0; i < keys.size(); ++i) 
        String key = keys.get(i);
        int value = values.get(i);
        System.out.print(key + "=" + value + "; ");
    
    System.out.println();

【讨论】:

A HashMultimap 将防止重复条目。但我仍然不清楚你的目标。 好的。我得到一个文本输入。这进入地图。关键是一个。这些值存储在 String[] 中。我稍后需要将这些值作为单独的字符串。所以这就是为什么它是 String[] 而不仅仅是字符串。我需要键值对中的每个组合,就像我的第一篇文章中一样。 在这种情况下,您只需要检查键值对是否已经存在于地图中。 我想我刚刚知道你想要地图的产品——就像***.com/questions/714108/… 好吧,更像是这样:***.com/questions/710670/…您的链接中给出的方法...如何将其应用于我的案例?对不起,我不是一个真正优秀的程序员......

以上是关于递归或迭代地从 HashMap 中检索键值组合的主要内容,如果未能解决你的问题,请参考以下文章

检索 HashMap 的迭代器会引发强制转换异常

递归地从链表中删除数据

如何在 Flutter Dart 中迭代 JSON Map 并检索键值结果?

如何在Java中递归地从N元素集中生成所有k元素子集

动态规划:0/1 背包 - 将组合检索为数组

Python3 - 排列组合的迭代