如何使用Java 8/lambda执行嵌套的“if”语句?

时间:2021-01-22 18:02:07

I have the following code and would like to implement it using lambda functions just for fun. Can it be done using the basic aggregate operations?

我有以下代码,并希望使用lambda函数来实现它。可以使用基本的聚合操作来完成吗?

List<Integer> result = new ArrayList<>();

for (int i = 1; i <= 10; i++) {
    if (10 % i == 0) {
        result.add(i);
        if (i != 5) {
            result.add(10 / i);
        }
    }
}

Using lambda:

使用λ:

List<Integer> result = IntStream.rangeClosed(1, 10)
                                .boxed()
                                .filter(i -> 10 % i == 0)
                                // a map or forEach function here?
                                // .map(return 10 / i -> if i != 5)
                                .collect(Collectors.toList());

5 个解决方案

#1


39  

The essential observation here is that your problem involves a non-isomorphic transformation: a single input element may map to zero, one, or two output elements. Whenever you notice this, you should immediately start looking for a solution which involves flatMap instead of map because that's the only way to achieve such a general transformation. In your particular case you can first apply filter for a one-to-zero element mapping, then flatMap for one-to-two mapping:

这里的基本观察是,您的问题涉及非同构转换:单个输入元素可能映射到零、一个或两个输出元素。无论何时您注意到这一点,您都应该立即开始寻找涉及到flatMap而不是map的解决方案,因为这是实现这种通用转换的唯一途径。在您的特定情况下,您可以首先为一对零元素映射应用过滤器,然后为一对二映射应用flatMap:

List<Integer> result =
    IntStream.rangeClosed(1, 10)
             .filter(i -> 10 % i == 0)
             .flatMap(i -> i == 5 ? IntStream.of(i) : IntStream.of(i, 10 / i))
             .boxed()
             .collect(toList());

#2


4  

You could declare a body for a lambda. For example:

你可以为一个lambda声明一个body。例如:

Runnable run = () -> System.out.println("Hey");

Could be

可能是

Runnable run = () -> {
    System.out.println("Hey");
};

Within that body, you can create nested statements:

在这个主体中,您可以创建嵌套语句:

Runnable run = () -> {
    int num = 5;

    if(num == 5) {
        System.out.println("Hey");
    }
};

#3


3  

Use flatMap as you are trying to add elements into the pipeline or a 1-to-many mapping. Map is a one to one mapping.

当您试图将元素添加到管道或一到多个映射时,请使用flatMap。Map是一对一映射。

ArrayList<Integer> result = (ArrayList<Integer>) IntStream.rangeClosed(1, 10)
                .boxed()
                .filter(i -> 10 % i == 0)
                .flatMap((Integer i) -> {return i!=5 ? Stream.of(i, (10/i)):Stream.of(i);})
                .collect(Collectors.toList());

This results in the same list as

这导致了相同的列表

ArrayList<Integer> result2 = new ArrayList<Integer>();

        for (int i = 1; i <= 10; i++) {
            if (10 % i == 0) {
                result2.add(i);
                if (i != 5) {
                    result2.add(10 / i);
                }
            }
        }

In case your wondering which way is faster the loop method is ~3 times faster than using streams.

如果您想知道哪种方式更快,循环方法比使用流快大约3倍。

Benchmark                     Mode  Cnt      Score     Error  Units
testStreams.Bench.loops       avgt    5     75.221 ±   0.576  ns/op
testStreams.Bench.streams     avgt    5    257.713 ±  13.125  ns/op

#4


1  

You can do this:

你可以这样做:

List<Integer> result1 = IntStream
    .rangeClosed(1, 10)
    .boxed()
    .filter(i -> 10 % i == 0)
    .map(i -> (i != 5 ? Stream.of(i, 10 / i) : Stream.of(i)))
    .flatMap(Function.identity())
    .collect(Collectors.toList());

#5


0  

Try using flatMap:

试着用flatMap:

List<Integer> result = IntStream.rangeClosed(1, 10)
        .boxed()
        .flatMap((i) -> {
            List<Integer> results = new ArrayList<>();
            if (10 % i == 0) {
                results.add(i);
                if (i != 5) {
                    results.add(10 / i);
                }
            }
            return results.stream();
        })
        .collect(Collectors.toList());

See http://ideone.com/EOBiEP

参见http://ideone.com/EOBiEP

#1


39  

The essential observation here is that your problem involves a non-isomorphic transformation: a single input element may map to zero, one, or two output elements. Whenever you notice this, you should immediately start looking for a solution which involves flatMap instead of map because that's the only way to achieve such a general transformation. In your particular case you can first apply filter for a one-to-zero element mapping, then flatMap for one-to-two mapping:

这里的基本观察是,您的问题涉及非同构转换:单个输入元素可能映射到零、一个或两个输出元素。无论何时您注意到这一点,您都应该立即开始寻找涉及到flatMap而不是map的解决方案,因为这是实现这种通用转换的唯一途径。在您的特定情况下,您可以首先为一对零元素映射应用过滤器,然后为一对二映射应用flatMap:

List<Integer> result =
    IntStream.rangeClosed(1, 10)
             .filter(i -> 10 % i == 0)
             .flatMap(i -> i == 5 ? IntStream.of(i) : IntStream.of(i, 10 / i))
             .boxed()
             .collect(toList());

#2


4  

You could declare a body for a lambda. For example:

你可以为一个lambda声明一个body。例如:

Runnable run = () -> System.out.println("Hey");

Could be

可能是

Runnable run = () -> {
    System.out.println("Hey");
};

Within that body, you can create nested statements:

在这个主体中,您可以创建嵌套语句:

Runnable run = () -> {
    int num = 5;

    if(num == 5) {
        System.out.println("Hey");
    }
};

#3


3  

Use flatMap as you are trying to add elements into the pipeline or a 1-to-many mapping. Map is a one to one mapping.

当您试图将元素添加到管道或一到多个映射时,请使用flatMap。Map是一对一映射。

ArrayList<Integer> result = (ArrayList<Integer>) IntStream.rangeClosed(1, 10)
                .boxed()
                .filter(i -> 10 % i == 0)
                .flatMap((Integer i) -> {return i!=5 ? Stream.of(i, (10/i)):Stream.of(i);})
                .collect(Collectors.toList());

This results in the same list as

这导致了相同的列表

ArrayList<Integer> result2 = new ArrayList<Integer>();

        for (int i = 1; i <= 10; i++) {
            if (10 % i == 0) {
                result2.add(i);
                if (i != 5) {
                    result2.add(10 / i);
                }
            }
        }

In case your wondering which way is faster the loop method is ~3 times faster than using streams.

如果您想知道哪种方式更快,循环方法比使用流快大约3倍。

Benchmark                     Mode  Cnt      Score     Error  Units
testStreams.Bench.loops       avgt    5     75.221 ±   0.576  ns/op
testStreams.Bench.streams     avgt    5    257.713 ±  13.125  ns/op

#4


1  

You can do this:

你可以这样做:

List<Integer> result1 = IntStream
    .rangeClosed(1, 10)
    .boxed()
    .filter(i -> 10 % i == 0)
    .map(i -> (i != 5 ? Stream.of(i, 10 / i) : Stream.of(i)))
    .flatMap(Function.identity())
    .collect(Collectors.toList());

#5


0  

Try using flatMap:

试着用flatMap:

List<Integer> result = IntStream.rangeClosed(1, 10)
        .boxed()
        .flatMap((i) -> {
            List<Integer> results = new ArrayList<>();
            if (10 % i == 0) {
                results.add(i);
                if (i != 5) {
                    results.add(10 / i);
                }
            }
            return results.stream();
        })
        .collect(Collectors.toList());

See http://ideone.com/EOBiEP

参见http://ideone.com/EOBiEP