Sławomir Lenart
Sławomir Lenart

Reputation: 8377

Python like range with stepping in pure Java

In [1]: range(-100, 100, 20)
Out[1]: [-100, -80, -60, -40, -20, 0, 20, 40, 60, 80]

What's the easiest way to create Array like above using standard libraries of Java instead of writting own function?

There is IntStream.range(-100, 100), but step is hardcoded to 1.


THIS IS NOT A DUPLICATE of Java: Equivalent of Python's range(int, int)?, because I need a step (offset) between numbers and want to use java built-in libraries instead of 3rd-party libraries. I've checked that question and answers before adding my own. The difference is subtle but essential.

Upvotes: 1

Views: 974

Answers (4)

Michał Krzywański
Michał Krzywański

Reputation: 16910

The same could be achieved with IntStream::iterate (available since JDK9) which takes seed, IntPredicate and IntUnaryOperator. With usage of helper method it would look like:

public static int[] range(int min, int max, int step) {
        return IntStream.iterate(min, operand -> operand < max, operand -> operand + step)
                .toArray();
}

Upvotes: 5

lczapski
lczapski

Reputation: 4120

Other way:

List<Integer> collect = Stream.iterate(-100, v -> v + 20).takeWhile(v -> v < 100)
    .collect(Collectors.toList());

Similar version with IntStream:

List<Integer> collect = IntStream.iterate( -100, v -> v + 20).takeWhile(v -> v < 100)
    .boxed().collect(Collectors.toList());

But based this answer above codes can be change to (with IntStream or Stream)

List<Integer> collect = Stream.iterate(-100, v -> v < 100, v -> v + 20)
    .collect(Collectors.toList());

Upvotes: 2

user11044402
user11044402

Reputation:

Using IntStream::range should work (for your special step of 20).

IntStream.range(-100, 100).filter(i -> i % 20 == 0);

A general implementation allowing negative steps could look like this:

/**
 * Generate a range of {@code Integer}s as a {@code Stream<Integer>} including
 * the left border and excluding the right border.
 * 
 * @param fromInclusive left border, included
 * @param toExclusive   right border, excluded
 * @param step          the step, can be negative
 * @return the range
 */
public static Stream<Integer> rangeStream(int fromInclusive,
        int toExclusive, int step) {
    // If the step is negative, we generate the stream by reverting all operations.
    // For this we use the sign of the step.
    int sign = step < 0 ? -1 : 1;
    return IntStream.range(sign * fromInclusive, sign * toExclusive)
            .filter(i -> (i - sign * fromInclusive) % (sign * step) == 0)
            .map(i -> sign * i)
            .boxed();
}

See https://gist.github.com/lutzhorn/9338f3c43b249a618285ccb2028cc4b5 for a detailed version.

Upvotes: 8

Diamond
Diamond

Reputation: 3428

It could be better to iterate only necessary sequences.

IntStream.range(-100 / 20, 100 / 20).map(i -> i * 20); // only iterate [-5, 5] items

Upvotes: 0

Related Questions