如何使用java lambda按相似键分组?

如何使用java lambda按相似键分组?,java,lambda,java-stream,Java,Lambda,Java Stream,我有一个列表,元素的一个字段以一些相同的字符开头,我想对列表进行分组 class Foo{ String a; String b; ... } 我怎样才能得到结果 输入 试试这个 List<Foo> list = new ArrayList<>(); list.add(new Foo("FM11","1")); list.add(new Foo("FM11","2")); Map<String,List<String>

我有一个列表,元素的一个字段以一些相同的字符开头,我想对列表进行分组

class Foo{
        String a;
        String b;
...
}

我怎样才能得到结果

输入

试试这个

List<Foo> list = new ArrayList<>();
list.add(new Foo("FM11","1"));
list.add(new Foo("FM11","2"));
Map<String,List<String>> result =  list.stream()
    .collect(Collectors.toMap(foo -> foo.getA(), foo -> list.stream()
        .filter(foo2-> foo2.getA().substring(0, 4).equals(foo.getA().substring(0, 4)))
        .map(Foo::getB)
        .collect(Collectors.toList())));
试试这个

List<Foo> list = new ArrayList<>();
list.add(new Foo("FM11","1"));
list.add(new Foo("FM11","2"));
Map<String,List<String>> result =  list.stream()
    .collect(Collectors.toMap(foo -> foo.getA(), foo -> list.stream()
        .filter(foo2-> foo2.getA().substring(0, 4).equals(foo.getA().substring(0, 4)))
        .map(Foo::getB)
        .collect(Collectors.toList())));

对于列表中的每个foo,您可以再次迭代列表,并过滤那些具有相同前缀的属性a out。暂时将其保存到临时变量并将其添加到地图中

    List<Foo> list = new ArrayList<>();
    list.add(new Foo("FM11","1"));
    list.add(new Foo("FM1122","2"));
    Map<String,List<String>> map = new HashMap<>();
    list.forEach(f -> {
        List<String> temp = list.stream()
                .filter(e->e.getA().substring(0, 4).equals(f.getA().substring(0, 4)))
                .map(e->e.getB())
                .collect(Collectors.toList());

        map.computeIfAbsent(f.getA(), k -> new ArrayList<>()).addAll(temp);
    });
    System.out.println(map);

对于列表中的每个foo,您可以再次迭代列表,并过滤那些具有相同前缀的属性a out。暂时将其保存到临时变量并将其添加到地图中

    List<Foo> list = new ArrayList<>();
    list.add(new Foo("FM11","1"));
    list.add(new Foo("FM1122","2"));
    Map<String,List<String>> map = new HashMap<>();
    list.forEach(f -> {
        List<String> temp = list.stream()
                .filter(e->e.getA().substring(0, 4).equals(f.getA().substring(0, 4)))
                .map(e->e.getB())
                .collect(Collectors.toList());

        map.computeIfAbsent(f.getA(), k -> new ArrayList<>()).addAll(temp);
    });
    System.out.println(map);

属于同一组的所有键的列表都是相同的,因此在将它们映射到原始A值之前,可以通过为每个组只收集一个列表来节省工作

使用流API,解决方案可能如下所示

List<Foo> list = Arrays.asList(new Foo("FM11","1"), new Foo("FM1122","2"));

Map<String,List<String>> groups = list.stream()
    .collect(Collectors.groupingBy(foo -> foo.getA().substring(0, 4),
        Collectors.mapping(Foo::getB, Collectors.toList())));

Map<String,List<String>> result = list.stream()
    .collect(Collectors.toMap(Foo::getA, foo -> groups.get(foo.getA().substring(0, 4))));

result.forEach((k,v) -> System.out.println(k+" -> "+v));
如果不使用流API,则可以更有效地执行此操作。通过一个循环,我们可以一次性完成这两个操作,将在地图中查找组的工作减半

Map<String,List<String>> groups = new HashMap<>(), result = new HashMap<>();

for(Foo foo: list) {
  List<String> bList
      = groups.computeIfAbsent(foo.getA().substring(0, 4), x -> new ArrayList<>());
  bList.add(foo.getB());
  result.put(foo.getA(), bList);
}

结果是相同的。

属于同一组的所有键的列表都是相同的,因此您可以通过在将它们映射到原始A值之前只为每个组收集一个列表来保存工作

使用流API,解决方案可能如下所示

List<Foo> list = Arrays.asList(new Foo("FM11","1"), new Foo("FM1122","2"));

Map<String,List<String>> groups = list.stream()
    .collect(Collectors.groupingBy(foo -> foo.getA().substring(0, 4),
        Collectors.mapping(Foo::getB, Collectors.toList())));

Map<String,List<String>> result = list.stream()
    .collect(Collectors.toMap(Foo::getA, foo -> groups.get(foo.getA().substring(0, 4))));

result.forEach((k,v) -> System.out.println(k+" -> "+v));
如果不使用流API,则可以更有效地执行此操作。通过一个循环,我们可以一次性完成这两个操作,将在地图中查找组的工作减半

Map<String,List<String>> groups = new HashMap<>(), result = new HashMap<>();

for(Foo foo: list) {
  List<String> bList
      = groups.computeIfAbsent(foo.getA().substring(0, 4), x -> new ArrayList<>());
  bList.add(foo.getB());
  result.put(foo.getA(), bList);
}

结果是相同的。

…stream.collectCollectors.groupingBy…根据您的示例输入,我看不出应该如何计算输出。你只想得到与每个a关联的所有b的叉积吗?我想得到一个所有a都类似于键的映射,然后在Foo中用类似的a,b->toListuse Collectors.partitionBy获得b,如果你只有两个值。否则,groupingBy.group by substring0,4。作为旁注,您知道吗?“…stream.collectCollectors.groupingBy…”给定您的示例输入,我不知道应该如何计算输出。你只想得到与每个a关联的所有b的叉积吗?我想得到一个所有a都类似于键的映射,然后在Foo中用类似的a,b->toListuse Collectors.partitionBy获得b,如果你只有两个值。否则,groupingBy.group by substring0,4。作为旁注,您知道吗?我认为OP希望使用Foo.a作为键,并将其Foo.a与当前键具有相同前缀的所有Foo.b添加到值列表中。他的列表只有两个条目,不包括例如list.addnew FooFM11,2;您包含了哪些内容。@厄立特里亚人嗯……不确定实际需求是什么,因为OP只是简单地说用java lambdata按相似键分组,这是非常低效的二次时间复杂性。它还创建了许多不必要的子字符串实例。您可以使用foo2.getA.regionMatches0、foo.getA、0、4代替foo2.getA.substring0、4.equalsfoo.getA.substring0、4。但它并不能解决执行list.size×list.size操作的一般问题……我认为OP希望使用Foo.a作为键,并将其Foo.a具有与当前键相同前缀的所有Foo.b添加到值列表中。他的列表只有两个条目,不包括例如list.addnew FooFM11,2;您包含了哪些内容。@厄立特里亚人嗯……不确定实际需求是什么,因为OP只是简单地说用java lambdata按相似键分组,这是非常低效的二次时间复杂性。它还创建了许多不必要的子字符串实例。您可以使用foo2.getA.regionMatches0、foo.getA、0、4代替foo2.getA.substring0、4.equalsfoo.getA.substring0、4。但它不能解决执行list.size×list.size操作的一般问题…