我上了这个课:
class A {
private List<String> keys;
private String otherData;
private int otherDate2;
// getter and setters for each
}
对于此类,我有一个简单的列表,其中填充了一些数据。 List<A> listOfA
。
现在,我想将此数据转换为地图。 Map<String, List<A>>
当前,我们使用多种方法以非常复杂的方式对其进行存档。我认为,我们可以通过简单的stream()
操作来解决它。
我尝试过
// first
listOfA.stream()
.collect(Colletors.groupingBy(a -> a.getKeys()))
// produces a Map<String, List<A>>
// second
listOfA.stream()
.flatMap(a -> a.getKeys().stream())
.collect(Colletors.groupingBy(string -> string))
// produces a Map<String, List<String>>
在这种情况下正确的方法是什么?
编辑:为清楚起见,我要一个Map<String, List<A>>
。
答案 0 :(得分:5)
您不需要流。这样比较容易:
Map<String, List<A>> result = new HashMap<>();
listOfA.forEach(a -> a.getKeys().forEach(key ->
result.computeIfAbsent(key, k -> new ArrayList<>()).add(a)));
这将迭代外部列表和内部列表,并使用Map
填充computeIfAbsent
,如果给定键仍然没有值,则会创建一个空列表,然后只需添加A
实例到相应的列表。
答案 1 :(得分:3)
第一个代码将按Map<List<String>, List<A>>
而不是Map<String, List<A>>
分组。
第二个代码没有意义:您将字符串自己分组...
一种简单的方法是创建所有可能的A键对的集合。
您可以为每对夫妇使用Map
,但看起来有些麻烦。
代表键和值的SimpleImmutableEntry
比较合适。
一旦获得全部夫妇,您就可以轻松地通过按键对A元素进行分组。
您可以尝试:
import static java.util.stream.Collectors.groupingBy;
import static java.util.stream.Collectors.mapping;
import static java.util.stream.Collectors.toList;
// ...
List<A> listOfA = new ArrayList<>();
listOfA.add(new A(Arrays.asList("1", "2"), "foo1", 1));
listOfA.add(new A(Arrays.asList("2", "3"), "foo2", 2));
listOfA.add(new A(Arrays.asList("3", "4"), "foo3", 3));
Map<String, List<A>> map =
listOfA.stream()
.flatMap(a -> a.keys.stream()
.map(k -> new SimpleImmutableEntry<>(k, a)))
.collect(groupingBy(e -> e.getKey(), mapping(e -> e.getValue(), toList())));
map.forEach((k, v) -> System.out.println("key=" + k + ", value=" + v + "\n"));
输出:
key = 1,值= [A [keys = [1、2],otherData = foo1,otherDate2 = 1]]
key = 2,值= [A [keys = [1,2],otherData = foo1,otherDate2 = 1],A [keys = [2,3],otherData = foo2,otherDate2 = 2]]
key = 3,值= [A [keys = [2,3],otherData = foo2,otherDate2 = 2],A [keys = [3,4],otherData = foo3,otherDate2 = 3]]
key = 4,值= [A [keys = [3,4],otherData = foo3,otherDate2 = 3]]
答案 2 :(得分:0)
如果要按某个字段对给定的集合进行分组,并且每个组可以包含多个对象。这是我的GroupUtils
的一部分:
public static <K, V> Map<K, List<V>> groupMultipleBy(Collection<V> data, Function<V, K> classifier) {
return Optional.ofNullable(data).orElse(Collections.emptyList()).stream().collect(Collectors.groupingBy(classifier, Collectors.mapping(Function.identity(), Collectors.toList())));
}
使用示例。
您有以下课程:
class A {
private String id;
private String name;
}
并且要分组此类的集合,可以使用:
List<A> collection = Collections.emptyList();
Map<String, List<A>> groupedById = GroupUtils.groupMultipleBy(collection, A::getId);
P.S。
要给您更多选择,请参见我的GroupUtils
的相对部分:
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public final class GroupUtils {
public static <K, V> Map<K, List<V>> groupMultipleBy(Collection<V> data, Function<V, K> classifier) {
return groupMultipleBy(data, classifier, Function.identity());
}
public static <K, V, S> Map<K, List<S>> groupMultipleBy(Collection<V> data, Function<V, K> classifier, Function<V, S> mapper) {
return groupMultipleBy(data, classifier, mapper, Collectors.toList());
}
public static <K, V, S, R extends Collection<S>> Map<K, R> groupMultipleBy(Collection<V> data, Function<V, K> classifier,
Collector<S, ?, R> downstream) {
return groupMultipleBy(data, classifier, (Function<V, S>)Function.identity(), downstream);
}
public static <K, V, S, R extends Collection<S>> Map<K, R> groupMultipleBy(Collection<V> data, Function<V, K> classifier,
Function<V, S> mapper, Collector<S, ?, R> downstream) {
return Optional.ofNullable(data).orElse(Collections.emptyList()).stream()
.collect(Collectors.groupingBy(classifier, Collectors.mapping(mapper, downstream)));
}
public static <K, V> Map<K, V> groupSingleBy(Collection<V> data, Function<V, K> keyMapper) {
return groupSingleBy(data, keyMapper, Function.identity());
}
public static <K, V, S> Map<K, S> groupSingleBy(Collection<V> data, Function<V, K> keyMapper, Function<V, S> valueMapper) {
return Optional.ofNullable(data).orElse(Collections.emptyList()).stream().collect(Collectors.toMap(keyMapper, valueMapper));
}
}