使用 lambda 根据列表的 Id 对列表中的对象进行分组
Posted
技术标签:
【中文标题】使用 lambda 根据列表的 Id 对列表中的对象进行分组【英文标题】:Use lambda to group an object within a list according to the Id of the list 【发布时间】:2022-01-04 05:04:30 【问题描述】:晚安,我需要一些帮助来使用 Java 8 (lambda) 对对象列表进行分组
我有我的实体 QuestionEventDTO
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public class QuestionEventDTO
public Long id;
public QuestionDTO question;
public List<QuestionDTO> questions;
当我咨询银行时,我得到了这样的外向回复:
QuestionEventDTO [id=1, question= QuestionDTO [id=1, description="Are you Dev"], questions =[]]
QuestionEventDTO [id=1, question= QuestionDTO [id=2, description="What's rating?"], questions = []]
QuestionEventDTO [id=2, question= QuestionDTO [id=3, description="What's your dog's name?"], questions = []]
QuestionEventDTO [id=2, questao= QuestionDTO [id=4, description="Are you Dev?"], questions = []]
但是,请注意 EventQuestion_id 是重复的,只有对象 QuestionDto 具有不同的 id。我想将 QuestionsDto 分组到一个 QuestionEvent 中,如下所示:
QuestionEventDTO [id=1, question= null, questions =[ QuestaoDTO [id=1, description="Are you Dev"], QuestaoDTO [id=2, description="What's rating?"] ] ]
QuestionEventDTO [id=2, question= null, questions =[ QuestaoDTO [id=3, description="What's your dog's name?"], QuestaoDTO [id=4, description="Are you Dev?"] ] ]
有人可以帮助我使用 lambda 找到一个好的解决方案吗?它是快速和高效的吗?谢谢。
【问题讨论】:
【参考方案1】:您可以尝试像这样添加注释 @EqualsAndHashCode(exclude = "question", "questions")
【讨论】:
【参考方案2】:我认为这不是最好的方法,但我正在分享你想要的结果。
allList.stream()
.collect(Collectors.groupingBy(QuestionEventDTO::getId))
.entrySet()
.stream()
.map(e ->
QuestionEventDTO newInstance = new QuestionEventDTO();
newInstance.setId(e.getKey());
newInstance.setQuestions(e.getValue().stream().map(v -> v.getQuestion()).collect(Collectors.toList()));
return newInstance;
).collect(Collectors.toList());
【讨论】:
【参考方案3】:这里需要将QuestionEventDTO
重新映射到新实例,并将question
字段设置为null
,并填充列表。
这可以使用带有合并功能的Collectors.toMap
来实现(和Supplier<Map>
提供LinkedHashMap
并保持插入顺序):
List<QuestionEventDto> questionEvents; // input list
List<QuestionEventDto> groupedById = new ArrayList<>(questionEvents
.stream() // Stream<QuestionEventDto>
.collect(Collectors.toMap(
QuestionEventDto::getId, // key
qe -> new QuestionEventDto(
qe.getId(), null, new ArrayList(Arrays.asList(qe.getQuestion()))
), // use all-args constructor
(qe1, qe2) ->
qe1.getQuestions().addAll(qe2.getQuestions());
return qe1;
,
LinkedHashMap::new // keep insertion order
)) // Map<Long, QuestionEventDto> created
.values() // Collection<QuestionEventDto>
); // convert to ArrayList<QuestionEventDto>
另一种解决方案可能是使用Collectors.groupingBy
+ Collectors.mapping
:
List<QuestionEventDto> questionEvents; // input list
List<QuestionEventDto> groupedById = questionEvents
.stream()
.collect(Collectors.groupingBy(
QuestionEventDto::getId, // key
LinkedHashMap::new,
Collectors.mapping(
QuestionEventDto::getQuestion, Collectors.toList()
) // value - List<QuestionDto>
))
.entrySet()
.stream() // Stream<Map.Entry<Long, List<QuestionDto>>>
.map(e -> new QuestionEventDto(e.getKey(), null, e.getValue()))
.collect(Collectors.toList());
【讨论】:
以上是关于使用 lambda 根据列表的 Id 对列表中的对象进行分组的主要内容,如果未能解决你的问题,请参考以下文章