spring 使用Java流API从平面对象列表形成集合结构

0yg35tkg  于 2023-03-22  发布在  Spring
关注(0)|答案(1)|浏览(102)

我有以下对象的平面列表:

public class FlatQuestion{
   public int QuestionId;
   public String QuestionName;
   public int SectionId;
   public String SectionName;
   public int FieldId;
   public String FieldName;
   public int Input_Type_Id;
   public String Input_Type_String;
}

我一直在试着把它转换成问题列表。

public class Question {

    public int id;
    public String name;
    public List<Section> sections;

    Question(String name, int id, List<Section> sections) {
        this.name = name;
        this.id = id;
        this.sections = sections;
    }
}

public class Section {
    
    public int id;
    public String name;
    public List<Field> fields;

    Section(int id, String name, List<Field> fields) {
        this.name = name;
        this.id = id;
    this.fields = fields;
    }

}

public class Field {

    public int id;
    public String lable;
    public Input input_type;

    Field(int id, String lable, Input input_type) {
    this.id = id;
    this.lable = lable;
        this.input_type = input_type;
    }
}

public class Input {

    public int id;
    public String type;

    Input(int id, String type) {
    this.id = id;
    this.type = type;
    }
}

我一直在努力的解决方案是给我多个部分。如何在这里获得不同的值:

final List<Question> results = data
    .stream()
    // extracting distinct questions, you have fetched  
    .map(FlatQuestion::QuestionId)
    .distinct()
    // now we have unique key for the data and can map it
    .map(it -> 
         new Question(
             it, 
             // extracting all sections, which  were fetched in rows with references to templates.
             data
                 .stream()
                 .filter(o -> o.QuestionId.equals(it))
                 .map(ing -> new Sections(ing.SectionId, ing.SectionName))
                 .collect(Collectors.toSet())
    .collect(Collectors.toList()) ;

添加一些示例数据:

FlatQuestion f1 = new FlatQuestion(1, "Student Survey", 1, "Basic info", 1, "Enter Name", 1, "Text");
FlatQuestion f2 = new FlatQuestion(1, "Student Survey", 1, "Basic info", 2, "Enter Address", 1, "Text");
FlatQuestion f3 = new FlatQuestion(1, "Student Survey", 2, "Class Info", 3, "Select No of subjects", 2, "Dropdown");
FlatQuestion f4 = new FlatQuestion(1, "Student Survey", 2, "Class info", 4, "Enter primary subject", 1, "Text");
FlatQuestion f5 = new FlatQuestion(2, "Patient Audit", 3, "Basic info", 5, "Enter Name", 1, "Text");
FlatQuestion f6 = new FlatQuestion(2, "Patient Audit", 3, "Basic info", 6, "Enter Address", 1, "Text");
FlatQuestion f7 = new FlatQuestion(2, "Patient Audit", 4, "Alcohol Consumption", 7, "How often you drink", 3, "Checkbox");
a2mppw5e

a2mppw5e1#

让我们一步一步来,首先,我们需要一个从FlatQeustionMap/创建Question的方法(假设没有重复项):

private Question mapQuestion(FlatQuestion flatQuestion) {
    return new Question(
            flatQuestion.getQuestionId(),
            flatQuestion.getQuestionName(),
            List.of(new Section(
                    flatQuestion.getSectionId(),
                    flatQuestion.getSectionName(),
                    List.of(new Field(
                            flatQuestion.getFieldId(),
                            flatQuestion.getFieldName(),
                            new Input(
                                    flatQuestion.getInput_Type_Id(),
                                    flatQuestion.getInput_Type_String()
                            ))
                    ))
            ));
}

然后,对于重复的,让我们从底部开始。当我们合并2个Question对象时,我们需要合并它们的Sections列表,避免重复,所以我们需要一个方法来合并两个List避免重复。它可以是这样的:

private List<Section> mergeSections(List<Section> sections, List<Section> otherSections) {
        // we'll group sections by section id and merge the duplicates with the merge function
        Map<Integer, Section> allSectionsById = Stream.concat(sections.stream(), otherSections.stream())
                .collect(Collectors.toMap(Section::getId, s -> s, this::mergeSectionsWithSameId));
        // the map has no duplicates now, we can safely return the values as a list
        return new ArrayList<>(allSectionsById.values());
}

正如你所看到的,Collectors.toMap允许我们为键指定一个Map器(在我们的例子中,Section::getId,一个值的Map器,和一个mergeFunction)。当我们有两个元素具有相同的键时,这个合并函数将被调用。在我们的例子中,我们将使用这两个具有相同键的Sections来创建一个包含所有字段的合并函数:

private Section mergeSectionsWithSameId(Section first, Section second) {
    if (first.getId() != second.getId()) {
        throw new IllegalArgumentException("cannot merge questions with different ids");
    }
    List<Field> allFields = new ArrayList<>();
    allFields.addAll(first.getFields());
    allFields.addAll(second.getFields());
    return new Section(first.getId(), first.getName(), allFields);
}

这意味着我们可以向上移动一级,并使用此函数合并两个具有相同id的问题:

private Question mergeQuestionsWithSameId(Question first, Question second) {
    if (first.getId() != second.getId()) {
        throw new IllegalArgumentException("cannot merge questions with different ids");
    }
    return new Question(
            first.getId(),
            first.getName(),
            mergeSections(first.getSections(), second.getSections())
    );
}

最后,让我们对问题流对象应用相同的技术:

Map<Integer, Question> questionById = Stream.of(f1, f2, f3, f4, f5, f6, f7)
    .collect(Collectors.toMap( FlatQuestion::getQuestionId, 
                               this::mapQuestion, 
                               this::mergeQuestionsWithSameId )
);

正如你所看到的,我们使用的是相同的Colllectors.toMap,我们将元素按questionId分组。此外,我们不再保持元素的原样(以前是q -> q),而是将它们从FlatQuestionMap到Question(使用q -> mapQuestion(q)或简单地使用this::mapQuestion)。
最后,我们使用(q1, a2) -> mergeQuestionsWithSameId(q1, q2)或简单的this::mergeQuestionsWithSameId处理具有相同id的问题。

相关问题