3

Below is Student class definition :

class Student{
    String name;
    int sub1;
    int sub2;
    int sub3;

    // etc...etc...
}

I have list of all students. Requirement is to get average of sub1, sub2 and sub3. And also get min mark and max mark in any subject for any student.

Below is the code for sub1:

    IntSummaryStatistics sub1Summary = students.stream().collect(Collectors.summarizingInt(s -> s.sub1));

Is it possible to do with single expression or I will have to create IntSummaryStatisticsfor each subject and compare each lowest and highest subj value?

Thanks in advance

Robby Goz
  • 57
  • 6
  • What do you mean by *min mark and max mark in any subject*? Do you want as result 3 `IntSummaryStatistics`, one summarizing `sub1`, one for `sub2` and one for `sub3`? Or is the minimum correlated between `sub`s? – Tunaki Apr 18 '16 at 10:55
  • There are list of students. I want to get min mark scored by student and max mark scored by student in any subject(sub1, sub2 or sub3) for any student. So I will have only one lowest and highest value for whole list – Robby Goz Apr 18 '16 at 10:57
  • And average marks for subject1, average marks for subject2 and average marks for subject3 – Robby Goz Apr 18 '16 at 10:59
  • No one-liner, sorry. If you want some reading check [this thread](http://stackoverflow.com/questions/32071726/), [that one](http://stackoverflow.com/questions/29181682/) or [yet another thread](http://stackoverflow.com/questions/36162262/)… – Holger Apr 18 '16 at 13:04
  • You'll need to write your own collector to summarize all your `sub`s, or create one `IntSummaryStatistics` for each `sub` – fps Apr 18 '16 at 13:13

1 Answers1

3

Try following :

  List<Student> students = Arrays.asList(Student.create("A", 60, 55, 35), 
                    Student.create("B", 40, 65, 75),
                    Student.create("C", 70, 45, 95));

        Map<String, IntSummaryStatistics> subjectsSummary = new HashMap<String, IntSummaryStatistics>();
        Map<String, List<Integer>> subjectMarks = new HashMap<String, List<Integer>>();

        List<Integer> sub1Marks = new ArrayList<>();
        List<Integer> sub2Marks = new ArrayList<>();
        List<Integer> sub3Marks = new ArrayList<>();

    // Input : Student
    // Output : Map(Key=SubjectName, Value= List of Marks for students)
    Function<Student, Map<String, List<Integer>>> toSubjectsMap = (s) -> {
        sub1Marks.add(s.getSub1());
        sub2Marks.add(s.getSub2());
        sub3Marks.add(s.getSub3());

        subjectMarks.put("Sub1", sub1Marks);
        subjectMarks.put("Sub2", sub2Marks);
        subjectMarks.put("Sub3", sub3Marks);

        return subjectMarks;
    };

    //Function to generate summary stats from the list of integers/marks
        Function<List<Integer>, IntSummaryStatistics> generateStatsFunc = (listOfMarks) -> {
            return listOfMarks.stream().collect(Collectors.summarizingInt(marks->marks));
        };


    // 1. Students are mapped to generate Map for subject-->List of Marks
    // 2. Doing flatMap on the generate Map to get the Keys from the map(list of subjects)
    // 3. Collecting the Keys(Subject Names) of Map to Map(Key=SubjectName,Value=IntSummaryStats for Subject)
    students.stream().map(toSubjectsMap).flatMap(subMap -> subMap.keySet().stream())
            .collect(() -> subjectsSummary/* Initial Value of Map */, (summary, key) -> {
                // Generate the stats from the list of marks for the subject 
                IntSummaryStatistics st = generateStatsFunc.apply(subjectMarks.get(key));
                //Adding the stats for each Subject into the result Summary
                summary.put(key, st);
            } , (summary1, summary2) -> {
                //merging the two maps
                summary1.putAll(summary2);
            });

    System.out.println(subjectsSummary);

and Student class as follows :

class Student {
    String name;
    int sub1;
    int sub2;
    int sub3;

    static Student create(String name, int sub1, int sub2, int sub3) {
        // validation
        return new Student(name, sub1, sub2, sub3);
    }

    public String getName() {
        return name;
    }

    public int getSub1() {
        return sub1;
    }

    public int getSub2() {
        return sub2;
    }

    public int getSub3() {
        return sub3;
    }

    private Student(String name, int sub1, int sub2, int sub3) {
        this.name = name;
        this.sub1 = sub1;
        this.sub2 = sub2;
        this.sub3 = sub3;
    }

    @Override
    public String toString() {
        return name;
    }
}
Chota Bheem
  • 1,106
  • 1
  • 13
  • 31
  • 1
    Fantastic.. Looks like I have to spend 5-6 hours for understanding that stream() block. Please add the comments if possible. – Robby Goz Apr 19 '16 at 12:14