通过字符串列表进行分组

时间:2018-09-11 14:32:29

标签: java

我上了这个课:

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>>

3 个答案:

答案 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));
    }

}