当前位置: 首页 > 知识库问答 >
问题:

Java8,Lambda:在分组列表中排序并将所有组合并到一个列表中

孔寒
2023-03-14

根据以下答案:https://stackoverflow.com/a/30202075/8760211

如何按stud\u id对每个组进行排序,然后返回一个包含所有学生的列表,作为按stud\u位置分组的结果,然后按stud\u id排序)?

将此作为现有Lambda表达式的扩展将非常好:

Map<String, List<Student>> studlistGrouped =
    studlist.stream().collect(Collectors.groupingBy(w -> w.stud_location));

我需要根据原始列表中元素的顺序进行分组。

First group: "New York"
Second group: "California"
Third group: "Los Angeles"

1726, "John", "New York"
4321, "Max", "California"
2234, "Andrew", "Los Angeles"
5223, "Michael", "New York"
7765, "Sam", "California"
3442, "Mark", "New York"

结果如下所示:

List<Student> groupedAndSorted = ....

    1726, "John", "New York"
    3442, "Mark", "New York"
    5223, "Michael", "New York"
    4321, "Max", "California"
    7765, "Sam", "California"
    2234, "Andrew", "Los Angeles"

我尝试了以下方法:

studlistGrouped.entrySet().stream().sorted(Comparator.compar‌​ing(Map.Entry::getVa‌​lue))

但这行不通。

共有3个答案

秋兴思
2023-03-14

由于结果应该是一个列表,所以您不需要分组,而只需排序(根据定义的规则更改顺序)。主要的障碍是,您希望在原始列表中第一次遇到位置后对其进行排序。

直接的方法是首先修复此位置顺序,然后进行单个排序操作:

Map<String,Integer> locationOrder = studlist.stream()
    .collect(HashMap::new,
             (m,s)->m.putIfAbsent(s.stud_location, m.size()),
             (m1,m2)->m2.keySet().forEach(l->m1.putIfAbsent(l, m1.size())));

studlist.sort(Comparator.comparingInt((Student s) -> locationOrder.get(s.stud_location))
                        .thenComparing(s -> s.stud_id));

如果您不能或不想修改原始列表,只需使用副本即可:

List<Student> result = new ArrayList<>(studlist);
result.sort(Comparator.comparingInt((Student s) -> locationOrder.get(s.stud_location))
                      .thenComparing(s -> s.stud_id));

也可以通过分组操作来解决此问题,但这并不容易:

List<Student> result = studlist.stream()
    .collect(Collectors.collectingAndThen(
                Collectors.groupingBy(s -> s.stud_location,
                                      LinkedHashMap::new, Collectors.toList()),
                m -> m.values().stream()
                      .flatMap(l -> l.stream().sorted(Comparator.comparing(s->s.stud_id)))
                      .collect(Collectors.toList())));

请注意,您必须收集到LinkedHashMap中以确保保留组的顺序。

汝繁
2023-03-14

如果我没说错的话,你需要一份清单

//first, use your function to group students
Map<String, List<Student>> studlistGrouped = students.stream()
        .collect(Collectors.groupingBy(Student::getLocation, Collectors.toList()));

//then sort groups by minimum id in each of them
List<Student> sorted = studlistGrouped.entrySet().stream()
        .sorted(Comparator.comparing(e -> e.getValue().stream().map(Student::getId).min(Comparator.naturalOrder()).orElse(0)))
        //and also sort each group before collecting them in one list
        .flatMap(e -> e.getValue().stream().sorted(Comparator.comparing(Student::getId))).collect(Collectors.toList());

这将产生以下结果:

Student{id='1726', name='John', location='New York'}
Student{id='3442', name='Mark', location='New York'}
Student{id='5223', name='Michael', location='New York'}
Student{id='2234', name='Andrew', location='Los Angeles'}
Student{id='4321', name='Max', location='California'}
Student{id='7765', name='Sam', location='California'}

也许这可以做得更优雅些,欢迎提出建议

编辑:在撰写此答案时,在OPs问题中没有提到根据原始列表中元素的顺序进行分组。所以我的假设是根据ID对列表和组进行排序。有关基于原始列表中顺序的解决方案,请参见其他答案,例如Holgers one

花飞扬
2023-03-14

不是100%清楚您是否需要Map

导入:

import static java.util.stream.Collectors.*;
import java.util.*;
import java.util.function.Function;

检索地图

Map<String, List<Student>> resultSet = studlist.stream()
      .collect(groupingBy(Student::getLocation,
             mapping(Function.identity(),
                  collectingAndThen(toList(),
                      e -> e.stream().sorted(Comparator.comparingInt(Student::getId))
                                            .collect(toList())))));

另一方面,如果您只想检索按给定属性排序的学生对象列表,那么执行分组方式、排序方式、收集方式,并以某种方式将地图值减少到单个列表中,将是一种资源浪费。而只是在列表中对学生对象进行排序,提供一个排序键,即。

studlist.sort(Comparator.comparingInt(Student::getId));

studlist.sort(Comparator.comparing(Student::getLocation));

或者,根据您是否希望按多个属性排序,您可以执行类似于shmosel的回答的操作。

 类似资料:
  • 问题内容: 例如,如果我有一个元组列表 如何解开元组并将其重新格式化为一个列表 我认为这也与功能有关,但是我真的不知道该怎么做。请赐教。 问题答案: b = [i for sub in a for i in sub] 这样就可以了。

  • 问题内容: 已关闭 。这个问题是基于观点的。它当前不接受答案。 想改善这个问题吗? 更新问题,以便通过编辑此帖子以事实和引用的形式回答。 7年前关闭。 改善这个问题 我想将排序的列表合并到一个列表中。这个解决方案如何?我相信它运行时间为O(n)。有任何明显的缺陷,效率低下或样式问题吗? 我真的不喜欢为“这是第一次迭代”设置标志并使用它来确保“最低”具有默认值的习惯用法。有没有更好的办法解决呢? 注

  • 我正试图想出一个分而治之的算法来合并j个排序列表和n个元素,但我被卡住了;我不知道如何把这个问题分成更小的子问题。我希望合并算法更高效,如下所示: 合并前两个列表;然后将结果列表与第三个列表合并;然后将结果列表与第四个列表合并,以此类推,该列表取O(j*jn)。

  • 问题内容: 我想将地图转换为: 至 结果列表是所有列表值的合并。 问题答案: 你可以有 这将检索映射的值,然后将每个列表平面映射到由其元素形成的Stream中,并将结果收集到列表中。 另一种选择是,不对每个列表进行平面映射,从而可能会提高性能,而无需对每个列表进行平面映射,则可以通过调用每个累加的结果来直接收集(由返回)。

  • 问题内容: 我正在尝试找出将两个列表合并为所有可能组合的最佳方法。因此,如果我从两个这样的列表开始: 结果列表如下所示: 也就是说,它基本上会生成一个列表列表,其中包含所有可能的组合。 我一直在通过itertools进行工作,我肯定可以找到答案,但是我无法提出一种使其以这种方式起作用的方法。我最接近的是: 哪个产生了: 因此,它会执行每个列表中所有可能的项目组合,但不会执行所有可能的结果列表。我如

  • 问题内容: 给出以下列表: 我想将它们按元组的第一,第二,第四和第五列进行分组,并对第三列求和。在此示例中,我将列命名为col1,col2,col3,col4,col5。 在SQL中,我将执行以下操作: 有没有一种“很酷”的方式来做到这一点,或者都是手动循环? 问题答案: (注意:重新格式化输出)