Home > Enterprise >  Stream average of streamed numbers and a constant
Stream average of streamed numbers and a constant

Time:07-03

Here's my code that returns a mark based on average score of tests done by a person.

    public Map<Person, String> defineMarks(Stream<CourseResult> results) {
    return results.collect(Collectors.toMap(CourseResult::getPerson,x->{
        double avg=x.getTaskResults().values().stream().collect(Collectors.summarizingInt(Integer::intValue)).getAverage();
        if(avg > 90) return "A";
        if(avg >= 83) return "B";
        if(avg >= 75) return "C";
        if(avg >= 68) return "D";
        if(avg >= 60) return "E";
        else return "F";
    }));
}

For reference here's CourseResult class

public class CourseResult {
    private final Person person;
    private final Map<String, Integer> taskResults;

    public CourseResult(final Person person, final Map<String, Integer> taskResults) {
        this.person = person;
        this.taskResults = taskResults;
    }

    public Person getPerson() {
        return person;
    }

    public Map<String, Integer> getTaskResults() {
        return taskResults;
    }
}

and 2 methods that generates test scores. historyResults

private final String[] practicalHistoryTasks = {"Shieldwalling", "Phalanxing", "Wedging", "Tercioing"};

private Stream<CourseResult> historyResults(final Random random) {
    int n = random.nextInt(names.length);
    int l = random.nextInt(lastNames.length);
    AtomicInteger t = new AtomicInteger(practicalHistoryTasks.length);

    return IntStream.iterate(0, i -> i   1)
            .limit(3)
            .mapToObj(i -> new Person(
                    names[(n   i) % names.length],
                    lastNames[(l   i) % lastNames.length],
                    18   random.nextInt(20)))
            .map(p -> new CourseResult(p,
                    IntStream.iterate(t.getAndIncrement(), i -> t.getAndIncrement())
                            .map(i -> i % practicalHistoryTasks.length)
                            .mapToObj(i -> practicalHistoryTasks[i])
                            .limit(3)
                            .collect(toMap(
                                    task -> task,
                                    task -> random.nextInt(51)   50))));
}

and programmingResults

    private final String[] programTasks = {"Lab 1. Figures", "Lab 2. War and Peace", "Lab 3. File Tree"};

 private Stream<CourseResult> programmingResults(final Random random) {
    int n = random.nextInt(names.length);
    int l = random.nextInt(lastNames.length);

    return IntStream.iterate(0, i -> i   1)
            .limit(3)
            .mapToObj(i -> new Person(
                    names[(n   i) % names.length],
                    lastNames[(l   i) % lastNames.length],
                    18   random.nextInt(20)))
            .map(p -> new CourseResult(p, Arrays.stream(programTasks).collect(toMap(
                    task -> task,
                    task -> random.nextInt(51)   50))));
}

So there are 3 test scores for each person. If I generate scores using programmingResults its fine because there are only 3 programming tests but if I generate scores using historyResults I also get 3 test scores per person but I should treat it as if the 4th test was not attempted at all which means 0 points for it. How can I make my defineMarks method get an average of collected test scores and in the case of historyResults get an average of collected test scores and a score of 0.

If my question is unclear please instruct me how to make it better :D

CodePudding user response:

I don't quite understand the point of the exercise. But if you want to add only one value to your stream and you can't modify the test score producing methods (there it would be easy to change the limit(3) to limit(4)) then may be you can use the task names to change the way of your calculation of the average, since all programTasks start with Lab ...:

return results.collect(
        Collectors.toMap(
                CourseResult::getPerson,
                x -> {
                    boolean areProgramTasks = x.getTaskResults().keySet().stream().allMatch(key -> key.startsWith("Lab "));
                    double avg;
                    if(areProgramTasks){
                        avg = x.getTaskResults().values().stream().collect(Collectors.summarizingInt(Integer::intValue)).getAverage();
                    }
                    else {
                        avg = Stream.concat(Stream.of(0), x.getTaskResults().values().stream()).collect(Collectors.summarizingInt(Integer::intValue)).getAverage();
                    }
                    if(avg >  90) return "A";
                    if(avg >= 83) return "B";
                    if(avg >= 75) return "C";
                    if(avg >= 68) return "D";
                    if(avg >= 60) return "E";
                    else return "F";
                }
        ));
  • Related