【问题标题】:Java 8: Filter an Array(NxM) to create a Map<String, HashSet<String>>Java 8:过滤数组(NxM)以创建 Map<String, HashSet<String>>
【发布时间】:2018-05-06 16:19:30
【问题描述】:

我想在 Java 8 中将 NxN 数组映射到 Map。

这个想法是每个 [i][0] 元素都是一个键,每个 j>0 的 [i][j] 是映射中每个键的值列表。

感谢您的帮助。 :)

这是我的课:

public class GroupingDishes {

    public static void main(String[] args) {

        String[][] dishes = {
                {"Salad", "Tomato", "Cucumber", "Salad", "Sauce"},
                {"Pizza", "Tomato", "Sausage", "Sauce", "Dough"},
                {"Quesadilla", "Chicken", "Cheese", "Sauce"},
                {"Sandwich", "Salad", "Bread", "Tomato", "Cheese"}
        };

        Map<String, HashSet<String>> groupDishes = groupingDishes(dishes);
    }

    public static Map<String, HashSet<String>> groupingDishes(String[][] dishes) {

        Map<String, HashSet<String>> mapFood = new HashMap<>();

        for (int i = 0; i < dishes.length; i++) {

            String food = dishes[i][0];

            for (int j = 0; j < dishes[i].length; j++) {

                if (mapFood.containsKey(food)) {

                    HashSet<String> existingIngredients = mapFood.get(dishes[i][0]);
                    existingIngredients.add(dishes[i][j]);
                    mapFood.put(food, existingIngredients);

                } else {

                    HashSet<String> newIngredient = new HashSet<>();
                    mapFood.put(food, newIngredient);

                }
            }
        }
        return mapFood;
    }
}

【问题讨论】:

    标签: java arrays lambda java-8 hashmap


    【解决方案1】:

    您可以将String[][] 转换为String[] 的流, 然后收集到地图, 使用String[] 的第一项作为键, 其余的作为集合的值。

    public static Map<String, HashSet<String>> groupingDishes2(String[][] dishes) {
        return Arrays.stream(dishes)
            .collect(Collectors.toMap(
                arr -> arr[0],
                arr -> Arrays.stream(arr).skip(1).collect(Collectors.toCollection(HashSet::new))));
    }
    

    顺便说一句,我怀疑你真的需要Map&lt;String, HashSet&lt;String&gt;&gt;。 最好把类型改成Map&lt;String, Set&lt;String&gt;&gt;, 然后实现也可以写得更简单。

    public static Map<String, Set<String>> groupingDishes(String[][] dishes) {
        return Arrays.stream(dishes)
            .collect(Collectors.toMap(
                arr -> arr[0],
                arr -> Arrays.stream(arr).skip(1).collect(Collectors.toSet())));
    }
    

    或者甚至更好,正如@Holger 建议的那样,一个更好的选择,因为 " 带有skip 和limit 的流表现不佳,Collectors 也没有得到任何关于结果初始值的提示容量”:

    public static Map<String, Set<String>> groupingDishes(String[][] dishes) {
        return Arrays.stream(dishes)
            .collect(Collectors.toMap(
                arr -> arr[0],
                arr -> new HashSet<>(Arrays.asList(arr).subList(1, arr.length))));
    }
    

    【讨论】:

    • 我不会对第二个函数使用流操作,而是使用arr -&gt; new HashSet&lt;&gt;(Arrays .asList(arr).subList(1, arr.length)) 或者创建一个列表:arr -&gt; Arrays.asList(Arrays .copyOfRange(arr, 1, arr.length))。
    • 我的建议中没有中间数组。第一个建议从包装原始数组的 view 创建一个集合。第二个建议创建一个列表,该列表包装 新数组。任何一个建议都比流操作更短、更有效。 skip 和 limit 的流表现不佳,Collectors 也没有得到任何关于结果初始容量的提示。
    • @Eugene: subList 仅创建数据视图,因此速度很快,但在存储结果时必须小心,因为它仍然引用原始数据(一个长于需要)。这就是为什么我只在传递给HashSet 的构造函数时使用它,该构造函数将复制一次数据。对于List 变体,我使用了Arrays.copyOfRange,因为Arrays.asList 不会复制。另一种选择是new ArrayList&lt;&gt;(Arrays.asList(arr).subList(1, arr.length)),但它更长……
    • @janos:第二个建议是针对 OP 实际上想要 List 的情况;它创建了一个新数组,这将是非常数组,最终列表将用作支持数组(Arrays.asList 不复制)。就像流操作将返回一个带有新后备数组的新集合一样。我只是使用了一种更简单的复制方法。可以在没有任何复制的情况下创建列表,引用原始数组,但是如果 OP 没有意识到,结果可能会表现出令人惊讶的行为,所以我不建议这样做。
    • 顺便说一句,您可以通过使用Arrays.stream(arr, 1, arr.length) 来避免这里的skip,但对于数组和/或集合之间的简单复制,Collections API 是惯用的选择。
    【解决方案2】:

    我能想到这个:

    Map<String, HashSet<String>> result = Arrays.stream(dishes)
                .map(x -> new AbstractMap.SimpleEntry<>(
                        x[0],
                        Arrays.stream(x).skip(1).collect(Collectors.toCollection(HashSet::new))))
                .collect(Collectors.toMap(Entry::getKey, Entry::getValue));
    

    【讨论】:

    • 不需要将key和value存储在中间的SimpleEntry中,只需要在后续的toMap收集器中提取即可。
    猜你喜欢
    • 1970-01-01
    • 2019-05-24
    • 2015-07-26
    • 2021-09-03
    • 2018-08-02
    • 2020-03-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多