【问题标题】:Loop through n number of maps循环n个地图
【发布时间】:2019-05-15 14:27:33
【问题描述】:

现在我有以下代码,它需要 2 个食谱并在食谱中找到重复项并“合并”它们。

public void mergeIngredients(Recipe recipe1, Recipe recipe2) {

    Map<String, Ingredients> recipe1Map = recipe1.getIngredientsMap();
    Map<String, Ingredients> recipe2Map = recipe2.getIngredientsMap();

    for (Map.Entry<String, Ingredients> s : recipe1Map.entrySet()) {

        if (recipe2Map.containsKey(s.getKey())) {
            double newValue = recipe1.getAmount(s.getKey()) + recipe2.getAmount(s.getKey());
            System.out.println(newValue);
        }
    }
}

我想更改此代码,因此我需要重构代码,以便它可以获取 N 个地图并比较所有地图,而不是只能相互检查 2 个地图。

示例: 用户输入了 8 个不同的食谱,它应该循环遍历所有这些并在发现重复时合并成分。实现这一目标的最佳方法是什么?

【问题讨论】:

标签: java loops maps


【解决方案1】:

我首先将所有Maps 中的所有密钥提取到Set 中。这将为您提供所有独特的成分键。

然后迭代该 Set 并从所有配方中获取所有值并将它们合并。

例如:

public void mergeIngredients(Set<Recipe> recipes) {

    Set<String> keys = recipes.stream()         //
            .map(Recipe::getIngredientsMap)     // Get the map
            .flatMap(m -> m.keySet().stream())  // Get all keys and make 1 big stream 
            .collect(Collectors.toSet());       // Collect them to a set

    for (String k : keys)
    {
        double newValue = recipes.stream()       //
                .map(Recipe::getIngredientsMap)  //
                .map(i->i.get(k))                //
                .mapToDouble(i->i.getAmount())   //
                .sum();                          //
        System.out.println(newValue);
    }

}

您可能可以更有效地做到这一点;但我认为这更容易理解。

【讨论】:

  • 谢谢!尽管double newValue = recipes.stream().map(Recipe::getIngredientsMap).map(i-&gt;i.get(k)).mapToDouble(Ingredients::getAmount).sum(); 我在这条线上得到了一个 NullPointer 你知道可能是什么问题吗?
【解决方案2】:

在重复键的情况下可以使用Merging Multiple Maps Using Java 8 Streams

public void mergerMap() throws Exception {
    Map<String, Integer> m1 = ImmutableMap.of("a", 2, "b", 3);
    Map<String, Integer> m2 = ImmutableMap.of("a", 3, "c", 4);

    Map<String, Integer> mx = Stream.of(m1, m2)
        .map(Map::entrySet)          // converts each map into an entry set
        .flatMap(Collection::stream) // converts each set into an entry stream, then
                                     // "concatenates" it in place of the original set
        .collect(
            Collectors.toMap(        // collects into a map
                Map.Entry::getKey,   // where each entry is based
                Map.Entry::getValue, // on the entries in the stream
                Integer::max         // such that if a value already exist for
                                     // a given key, the max of the old
                                     // and new value is taken
            )
        )
    ;

    Map<String, Integer> expected = ImmutableMap.of("a", 3, "b", 3, "c", 4);
    assertEquals(expected, mx);
}

【讨论】:

  • 这如何回答这个问题? (多张地图)
【解决方案3】:

我真的不认为您的成分需要地图,所以这里有一个替代解决方案。 如果你让你的 Ingredients 类实现 equals & hashcode 你可以直接在一个集合中使用它。当然,Recipe 中还有一个方法,它将所有成分作为List 返回。然后以下将返回所有独特的成分。

Set<Ingredients> merge(List<Recipe> recipies) {
    return recipies.stream().map(s -> s.allIngredients()).collect(Collectors.toSet()); 
}

【讨论】:

  • 这是因为我需要每种成分3个元素:数量+单位+描述示例:1磅鸡肉
  • @FrederikJorgensen,不确定我是否理解。那不是说您的Ingredients 班级有3 个成员吗? amount、“单位”和description?为什么需要地图?
猜你喜欢
  • 1970-01-01
  • 2023-03-14
  • 2013-10-11
  • 2011-03-02
  • 2016-05-18
  • 1970-01-01
  • 2022-09-27
  • 2012-12-29
  • 1970-01-01
相关资源
最近更新 更多