【问题标题】:Recursively or iteratively retrieve key-value combinations from a HashMap递归或迭代地从 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[]

标签: java recursion hashmap combinations cartesian-product


【解决方案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[] 而不仅仅是字符串。我需要键值对中的每个组合,就像我的第一篇文章中一样。
      • 在这种情况下,您只需要检查键值对是否已经存在于地图中。
      • 我想我刚刚知道你想要地图的产品——就像stackoverflow.com/questions/714108/…
      • 好吧,更像是这样:stackoverflow.com/questions/710670/…您的链接中给出的方法...如何将其应用于我的案例?对不起,我不是一个真正优秀的程序员......
      猜你喜欢
      • 1970-01-01
      • 2018-09-20
      • 1970-01-01
      • 2017-09-16
      • 1970-01-01
      • 2015-03-16
      • 2011-03-21
      • 2010-12-02
      • 1970-01-01
      相关资源
      最近更新 更多