javafor-loopif-statementlambdajava-stream

Replace IFs and FOR LOOPs with STREAMs and LAMBDAs


I want to optimalize my code. I used to use for loops and ifs, but I know that there is more faster ways than this. I am still pretty new to the lambdas and streams. For practise, I decided I replace my old codes with them. I am curious, how this code below could change.

        int counter = 0;
        List<Integer> points = new ArrayList<>();

        for (String name : names) {

            for (Car car : cars) {
                if (counter != 0) {
                    points.add(counter);
                }
                counter= 0;

                for (Driver driver : car.getDriversWhoDrivesIt()) {
                    if (driver.getYearsInMotorsport() == 15) {
                        if (!(names.contains(driver.getName()))) {
                            filteredCars.remove(car);
                            counter= 0;
                            break;
                        }
                    }

                    if (driver.getYearsInMotorsport() == 7 ) {
                        counter+= 7;
                    }

                    if (driver.getYearsInMotorsport() == 3) {
                        counter+= 3;
                    }
                   
                }

            }
        }

So the task here is that there is a list (names) with the drivers which earlier the user define. After that I iterate through all the drivers that drive that cars and if somebody has exactly 15 years of experience and the user not selected it (in the names list), than the car that the driver drived got eliminated (removed from the filteredCar and no need to continue with that car).

So for example I have 3 cars and the drivers with exp:

  1. car : Lewis(15years), Marco(4), Sebastian(15)
  2. car: Max(15), Amanda(7)
  3. car: Bob(15), George(3), Lando(15)

Than the user defines the names: Lewis, Bob, Amanda, Lando, Max

If the driver has 15 years of exp and the user not defined it, than I dont want that car in my filteredCars. And if all the 15 years of exp drivers defined I want to collect the other drivers exp(counter)

So in the end I want my filteredCar list like this: 2. car - 7 3.car - 3

Explanation: The first car got eliminated, because the user not defined Sebastian who has 15 years. The second and third car got promoted, because the user defined all the 15 years experienced drivers, and the second car got 7 point(cuz Amanda), and the third got 3 (George).

I tried to solve this problem with flatMap. But I am got stucked with the if-s. My problem is that I need to use inline if in lambdas but my if-s dont have else part.

        names.stream()
                .flatMap(name -> cars.stream()
                    .flatMap(car -> car.getDriversWhoDrivesIt().stream()
//                        .flatMap(driver -> driver.getYearsInMotorsport() == 5 ? ) //?? now what?
                    )
                );

I hope somebody can help me with this.


Solution

  • Instead of the list of names I would advise defining a Set. For each Car filter drivers that have exactly 15 year of experience and then check whether all they are present in the user-defined set of names using allMatch() operation.

    Then collect all the Car objects remained in the stream into a map using collector toMap():

    Set<String> names = Set.of("Lewis", "Bob", "Amanda", "Lando", "Max");
                
    List<Car> cars = List.of(
        new Car("Car1", List.of(new Driver("Lewis", 15),
                    new Driver("Marco", 4),
                    new Driver("Sebastian", 15))
                ),
        new Car("Car2", List.of(new Driver("Max", 15),
                    new Driver("Amanda", 7))
                ),
        new Car("Car3", List.of(new Driver("Bob", 15),
                    new Driver("George", 3),
                    new Driver("Lando", 15))
                )
    );
                
    Map<Car, Integer> pointByCar = cars.stream()
        .filter(car -> car.getDrivers().stream()
            .filter(driver -> driver.getYearsInMotorsport() == 15)
            .map(Driver::getName)
            .allMatch(names::contains)
        )
        .collect(Collectors.toMap(
            Function.identity(),
            car -> car.getDrivers().stream()
                .mapToInt(Driver::getYearsInMotorsport)
                .filter(i -> i == 7 || i == 3)
                .sum()
        ));
                
    pointByCar.forEach((car, points) -> System.out.println(car + " -> " + points));
    

    Output:

    Car{name='Car2'} -> 7
    Car{name='Car3'} -> 3
    

    A link to Online Demo