繁体   English   中英

用 STREAM 和 LAMBDA 替换 IF 和 FOR 循环

[英]Replace IFs and FOR LOOPs with STREAMs and LAMBDAs

我想优化我的代码。 我曾经使用 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 年的经验并且用户没有选择它(在名称列表中),那么司机驾驶的汽车就会被淘汰(从 filteredCar 中删除并且没有需要继续驾驶那辆车)。

因此,例如我有 3 辆汽车和带有 exp 的司机:

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

比用户定义的名称:Lewis、Bob、Amanda、Lando、Max

如果司机有 15 年的 exp 而用户没有定义它,那么我不希望那辆车出现在我的 filteredCars 中。 如果定义了所有 15 年的 exp 驱动程序,我想收集其他驱动程序 exp(counter)

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

解释:第一辆车被淘汰,因为用户没有定义有 15 年的 Sebastian。 第二和第三辆车得到提升,因为用户定义了所有 15 年有经验的司机,第二辆车得到 7 分(因为 Amanda),第三辆车得到 3 分(乔治)。

我试图用 flatMap 解决这个问题。 但是我被 if-s 困住了。 我的问题是我需要在 lambda 中使用 inline if 但我的 if-s 没有其他部分。

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

我希望有人可以帮助我。

我知道有比这更快的方法

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

在此示例中,我要从 stream 中删除具有 15 年经验的驾驶员且未在名称列表中列出的汽车。然后我将结果收集到 map 中。关键是汽车。 价值是司机年数的总和——拥有 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()));

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

然后使用收集器toMap()将 stream 中剩余的所有Car对象收集到 map 中:

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

在线演示链接

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM