Java 8 List into Map。

时间:2022-10-06 19:39:24

I want to convert List of Objects to Map, where Map's key and value located as attributes inside Object in List.

我想要将对象列表转换成Map,其中Map的键和值位于列表中对象的属性中。

Here Java 7 snippet of such convertation:

这里是Java 7的转换片段:

private Map<String, Child> getChildren(List<Family> families  ) {
        Map<String, Child> convertedMap = new HashMap<String, Child>();

        for (Family family : families) {
            convertedMap.put(family.getId(), family.getParent().getChild());
        }
        return convertedMap;
    }

2 个解决方案

#1


10  

It should be something similar to...

它应该是类似于…

Map<String, Child> m = families.stream()
    .collect(Collectors.toMap(Family::getId, f -> f.getParent().getChild()));

#2


8  

Jason gave a decent answer (+1) but I should point out that it has different semantics from the OP's Java 7 code. The issue concerns the behavior if two family instances in the input list have duplicate IDs. Maybe they're guaranteed unique, in which case there is no difference. If there are duplicates, though, with the OP's original code, a Family later in the list will overwrite the map entry for a Family earlier in the list that has the same ID.

Jason给出了一个不错的答案(+1),但我应该指出,它与OP的Java 7代码有不同的语义。如果输入列表中的两个家族实例有重复的id,那么问题就涉及到行为。也许它们是唯一的,在这种情况下没有区别。如果有副本,但是,在OP的原始代码中,稍后在列表中的一个家庭将会覆盖在具有相同ID的列表中较早的一个家庭的map条目。

With Jason's code (shown below, slightly modified):

使用Jason的代码(如下所示,稍作修改):

Map<String, Child> getChildren(List<Family> families) {
    return families.stream()
        .collect(Collectors.toMap(Family::getId, f -> f.getParent().getChild()));
}

the Collectors.toMap operation will throw IllegalStateException if there are any duplicate keys. This is somewhat unpleasant, but at least it notifies you that there are duplicates instead of potentially losing data silently. The rule for Collectors.toMap(keyMapper, valueMapper) is that you need to be sure that the key mapper function returns a unique key for every element of the stream.

收藏家。如果有任何重复键,toMap操作将抛出IllegalStateException。这有些令人不快,但至少它会通知您,有重复的数据,而不是潜在地丢失数据。收藏家的规则。toMap(keyMapper, valueMapper)是您需要确保键映射函数为流的每个元素返回唯一的键。

What you need to do about this -- if anything -- depends on the problem domain. One possibility is to use the three-arg version: Collectors.toMap(keyMapper, valueMapper, mergeFunction). This specifies an extra function that gets called in the case of duplicates. If you want to have later entries overwrite earlier ones (matching the original Java 7 code), you'd do this:

你需要做的事情——如果有的话——取决于问题领域。一种可能是使用“三个arg版本”:收藏家。toMap(keyMapper valueMapper mergeFunction)。这指定了在重复的情况下调用的额外函数。如果您希望以后的条目覆盖较早的条目(匹配原始的Java 7代码),您可以这样做:

Map<String, Child> getChildren(List<Family> families) {
    return families.stream()
        .collect(Collectors.toMap(Family::getId, f -> f.getParent().getChild(),
                                                 (child1, child2) -> child2));
}

An alternative would be to build up a list of children for each family instead of having just one child. You could write a more complicated merging function that created a list for the first child and appended to this list for the second and subsequent children. This is so common that there is a special groupingBy collector that does this automatically. By itself this would produce a list of families grouped by ID. We don't want a list of families but instead we want a list of children, so we add a downstream mapping operation to map from family to child, and then collect the children into a list. The code would look like this:

另一种方法是为每个家庭建立一个孩子的清单,而不是只生一个孩子。您可以编写一个更复杂的合并函数,为第一个孩子创建一个列表,并将其添加到第二个和后续的子列表中。这是很常见的,有一个特殊的groupingBy收集器,它会自动完成这个工作。我们不想要一个家庭列表,而是想要一个孩子的列表,所以我们添加了一个从家庭到孩子的映射操作,然后把孩子们收集到一个列表中。代码是这样的:

Map<String, List<Child>> getChildren(List<Family> families) {
    return families.stream()
        .collect(Collectors.groupingBy(Family::getId,
                    Collectors.mapping(f -> f.getParent().getChild(),
                        Collectors.toList())));
}

Note that the return type has changed from Map<String, Child> to Map<String, List<Child>>.

注意,返回类型已经从Map 到Map >。 ,> ,>

#1


10  

It should be something similar to...

它应该是类似于…

Map<String, Child> m = families.stream()
    .collect(Collectors.toMap(Family::getId, f -> f.getParent().getChild()));

#2


8  

Jason gave a decent answer (+1) but I should point out that it has different semantics from the OP's Java 7 code. The issue concerns the behavior if two family instances in the input list have duplicate IDs. Maybe they're guaranteed unique, in which case there is no difference. If there are duplicates, though, with the OP's original code, a Family later in the list will overwrite the map entry for a Family earlier in the list that has the same ID.

Jason给出了一个不错的答案(+1),但我应该指出,它与OP的Java 7代码有不同的语义。如果输入列表中的两个家族实例有重复的id,那么问题就涉及到行为。也许它们是唯一的,在这种情况下没有区别。如果有副本,但是,在OP的原始代码中,稍后在列表中的一个家庭将会覆盖在具有相同ID的列表中较早的一个家庭的map条目。

With Jason's code (shown below, slightly modified):

使用Jason的代码(如下所示,稍作修改):

Map<String, Child> getChildren(List<Family> families) {
    return families.stream()
        .collect(Collectors.toMap(Family::getId, f -> f.getParent().getChild()));
}

the Collectors.toMap operation will throw IllegalStateException if there are any duplicate keys. This is somewhat unpleasant, but at least it notifies you that there are duplicates instead of potentially losing data silently. The rule for Collectors.toMap(keyMapper, valueMapper) is that you need to be sure that the key mapper function returns a unique key for every element of the stream.

收藏家。如果有任何重复键,toMap操作将抛出IllegalStateException。这有些令人不快,但至少它会通知您,有重复的数据,而不是潜在地丢失数据。收藏家的规则。toMap(keyMapper, valueMapper)是您需要确保键映射函数为流的每个元素返回唯一的键。

What you need to do about this -- if anything -- depends on the problem domain. One possibility is to use the three-arg version: Collectors.toMap(keyMapper, valueMapper, mergeFunction). This specifies an extra function that gets called in the case of duplicates. If you want to have later entries overwrite earlier ones (matching the original Java 7 code), you'd do this:

你需要做的事情——如果有的话——取决于问题领域。一种可能是使用“三个arg版本”:收藏家。toMap(keyMapper valueMapper mergeFunction)。这指定了在重复的情况下调用的额外函数。如果您希望以后的条目覆盖较早的条目(匹配原始的Java 7代码),您可以这样做:

Map<String, Child> getChildren(List<Family> families) {
    return families.stream()
        .collect(Collectors.toMap(Family::getId, f -> f.getParent().getChild(),
                                                 (child1, child2) -> child2));
}

An alternative would be to build up a list of children for each family instead of having just one child. You could write a more complicated merging function that created a list for the first child and appended to this list for the second and subsequent children. This is so common that there is a special groupingBy collector that does this automatically. By itself this would produce a list of families grouped by ID. We don't want a list of families but instead we want a list of children, so we add a downstream mapping operation to map from family to child, and then collect the children into a list. The code would look like this:

另一种方法是为每个家庭建立一个孩子的清单,而不是只生一个孩子。您可以编写一个更复杂的合并函数,为第一个孩子创建一个列表,并将其添加到第二个和后续的子列表中。这是很常见的,有一个特殊的groupingBy收集器,它会自动完成这个工作。我们不想要一个家庭列表,而是想要一个孩子的列表,所以我们添加了一个从家庭到孩子的映射操作,然后把孩子们收集到一个列表中。代码是这样的:

Map<String, List<Child>> getChildren(List<Family> families) {
    return families.stream()
        .collect(Collectors.groupingBy(Family::getId,
                    Collectors.mapping(f -> f.getParent().getChild(),
                        Collectors.toList())));
}

Note that the return type has changed from Map<String, Child> to Map<String, List<Child>>.

注意,返回类型已经从Map 到Map >。 ,> ,>