用 STREAM 和 LAMBDA 替换 IF 和 FOR 循环

问题描述 投票:0回答:2

我想优化我的代码。我曾经使用 for 循环和 ifs,但我知道还有比这更快的方法。我对 lambda 表达式和流还很陌生。为了练习,我决定用它们替换我的旧代码。 我很好奇,下面的代码会如何改变。

        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;
                    }
                   
                }

            }
        }

因此,这里的任务是有一个包含用户之前定义的驱动程序的列表(名称)。之后,我遍历所有驾驶该汽车的驾驶员,如果有人恰好有 15 年的经验,并且用户没有选择它(在名称列表中),则该驾驶员驾驶的汽车将被淘汰(从过滤的汽车中删除,并且没有需要继续驾驶那辆车)。

例如,我有 3 辆车,司机有经验:

  1. 汽车:刘易斯(15年),马可(4),塞巴斯蒂安(15)
  2. 汽车:麦克斯(15),阿曼达(7)
  3. 汽车:鲍勃(15)、乔治(3)、兰多(15)

用户定义名称: 刘易斯、鲍勃、阿曼达、兰多、麦克斯

如果司机有 15 年的经验,而用户没有定义它,那么我不希望那辆车出现在我的过滤汽车中。 如果定义了所有 15 年的经验司机,我想收集其他司机的经验(计数器)

所以最后我想要我的filteredCar列表像这样: 2. 汽车 - 7 3.汽车 - 3

说明: 第一辆车被淘汰了,因为用户没有定义Sebastian已经15年了。 第二辆车和第三辆车得到了晋升,因为用户定义了所有 15 年经验的驾驶员,第二辆车得到了 7 分(因为阿曼达),第三辆车得到了 3 分(乔治)。

我尝试用 flatMap 来解决这个问题。但我被 if-s 困住了。我的问题是我需要在 lambda 中使用内联 if,但我的 if-s 没有 else 部分。

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

我希望有人能帮助我。

java for-loop if-statement lambda java-stream
2个回答
1
投票

我建议定义一个

Set
,而不是名称列表。对于每个
Car
过滤具有恰好
15
年经验的驱动程序,然后使用
allMatch()
操作检查它们是否全部存在于用户定义的名称集中。

然后使用收集器

Car
将流中剩余的所有
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));

输出:

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

在线演示链接


1
投票

我知道还有比这更快的方法

只是写得更快,有些人可能会发现它更具可读性。

在此示例中,我将从流中删除驾驶员拥有 15 年经验且未列在名称列表中的汽车。然后我将结果收集到地图中。关键是车。价值是驾驶员年限的总和 - 具有 15 年经验的驾驶员。

    Map<Car, Integer> filteredCars = cars.stream()
            .filter(car -> car.driversWhoDrivesIt().stream().allMatch(driver -> driver.yearsInMotorsport() != 15 || names.contains(driver.name())))
            .collect(Collectors.toMap(
                    Function.identity(),
                    car -> car.driversWhoDrivesIt().stream()
                            .mapToInt(Driver::yearsInMotorsport)
                            .filter(y -> y != 15)
                            .sum()));
© www.soinside.com 2019 - 2024. All rights reserved.