IntStream.iterate 具有要添加的交替值

IntStream.iterate with alternating values to add

我想创建一个整数序列,最好是 IntStream,它遵循一定的条件。一些简单的例子来解释我想做什么:

从 0 开始的前 10 个偶数的序列(这里我没有问题,我用下面的代码片段来做)

IntStream.iterate(0, i -> i + 2).limit(10); 

//0,2,4,6,8,10,12,14,16,18

从0开始的前10个数字的顺序,交替将2和3加到privious数字上;期望的输出:

 //0,2,5,7,10,12,15,17,20,22

我也很想在这种情况下使用 IntStream.iterate()IntStream.generate(),但我自己无法做到。我正在使用经典的 for 循环,它可以工作,但对于这样一个相对简单的任务来说有点长

List<Integer> list = new ArrayList<>();
list.add(0);
for(int i = 1, j = 1; i < 10; i++, j *= -1){
    if(j > 0){
        list.add(list.get(i-1) + 2);
    }
    else{
        list.add(list.get(i-1) + 3);
    }
}

//and then stream over the list to get IntStream
list.stream().mapToInt(Integer::intValue);

有什么简单的方法可以用 IntStream.iterate()IntStream.generate() 实现与上面相同的效果?

对于三个或更多的交替值,我不知道如何优雅地做到这一点。例如,如果我想创建从 0 开始的前 10 个数字的序列,方法是将 +2、+5 和 +7 交替添加到具有所需输出的前一个数字:

//0,2,7,14,16,21,28,30,35,42

我考虑过在带有 3 个 if-else 块或 switch 情况的 for 循环中使用 i%3 但是当我需要更多交替值并且我必须添加更多 ifscases。任何想法如何去做?如果您认为 IntStream.iterate()IntStream.generate() 不是解决所描述任务的正确方法,我也对其他方法持开放态度。

通过交替添加2或3来生成流,可以观察到每个other值都是5的倍数。因此如果前一个值可以被5整除没有余数就加2,否则加3。

IntStream.iterate(0, i -> (i % 5 == 0) ? (i + 2) : (i + 3)).limit(10)

对于两个交替的整数,在某些情况下这种方法是不可能的。如果其中一个数字是另一个数字的因数,那将是不可能的。例如2和4。

对于此类情况,您可以使用更通用的方法并在迭代器外部维护一个布尔值。

它不遵循函数式风格,因为你的函数有副作用,但是嘿,Java 不是函数式语言。够直观了。

AtomicBoolean isTwo = new AtomicBoolean(true);
IntStream.iterate(0, i -> isTwo.getAndSet(!isTwo.get()) ? (i + 2) : (i + 4))

对于 3 个交替值,在一般情况下,您可以执行与布尔值类似的操作,但使用在 0、1 和 2 之间循环的整数计数器。

AtomicInteger counter = new AtomicInteger(0);
IntStream.iterate(0, i -> {
        int count = counter.getAndUpdate(cnt -> (cnt + 1) % 3);
        if (count == 0) return i + 2;
        if (count == 1) return i + 5;
        if (count == 2) return i + 7;
        // As long as modulus value == number of if-conditions, this isn't possible
        throw new RuntimeException("Only 3 possible values");
    })
    .limit(10)

您可以使用 AtomicInteger 来实现这一点,并保留要以交替方式添加的数字列表。

List<Integer> adds = List.of(2,3,7);
AtomicInteger x = new AtomicInteger(0);
int limit = 10;
return IntStream.iterate(1,
   i -> i + adds.get(x.getAndIncrement() % adds.size()))
                .limit(limit)
                .boxed()
                .collect(Collectors.toList());

你可以从数学上看这个。假设您要交替添加 x1、x2、x3 ... xn。

前n项可以写成:

(0 * sum of all x's)
(0 * sum of all x's + x1)
(0 * sum of all x's + x1 + x2)
(0 * sum of all x's + x1 + x2 + x3)
...
(0 * sum of all x's + sum of all x's - xn)

接下来的n项可以用同样的方式写,除了你把所有的0都换成1。

(1 * sum of all x's)
(1 * sum of all x's + x1)
(1 * sum of all x's + x1 + x2)
(1 * sum of all x's + x1 + x2 + x3)
...
(1 * sum of all x's + sum of all x's - xn)

下一个 n 个术语,您将所有的 1 替换为 2,依此类推。

所以我们只需要生成流 (1, 2, 3, 4...) 和 flatMap 每个元素 i

的流
(i * sum of all x's)
(i * sum of all x's + x1)
(i * sum of all x's + x1 + x2)
(i * sum of all x's + x1 + x2 + x3)
...
(i * sum of all x's + sum of all x's - xn)

使用此模式,您可以像这样编写 2、5、7 流:

final int a = 2, 
final int b = 5, 
final int c = 7;
final int sum = a + b + c;
IntStream.iterate(0, i -> i + 1).flatMap(
    i -> IntStream.of(i * sum, i * sum + a, i * sum + a + b)
).limit(10);

如果您想改为执行 2、3、5、7:

final int a = 2, 
final int b = 3, 
final int c = 5; 
final int d = 7;
final int sum = a + b + c + d;
IntStream.iterate(0, i -> i + 1).flatMap(
    i -> IntStream.of(i * sum, i * sum + a, i * sum + a + b, i * sum + a + b + c)
).limit(10);

我会留给你将其概括为任何 int[] 个数字。