Stream / IntRange over 2D coordinates?
I have the following classes:
public class Rectangle
{
public int width, height;
public Point start;
public Rectangle(Point start, int width, int height)
{
this.start = start;
this.width = width;
this.height = height;
}
}
public class Point
{
public int x, y;
public Point(int x, int y)
{
this.x = x;
this.y = y;
}
}
I want to create a method of the Rectangle class to return Java 8 Stream
type Point
where it will place the indices in the rectangle. Ex.
// This is inside the rectangle class.
public Stream<Point> stream(int hstep, int vstep)
{
// if the rectangle started at 0,0
// and had a width and height of 100
// and hstep and vstep were both 1
// then the returned stream would be
// 0,0 -> 1,0 -> 2,0 -> ... -> 100,0 -> 0,1 -> 1,1 -> ...
// If vstep was 5 and h step was 25 it would return
// 0,0 -> 25,0 -> 50,0 -> 75,0 -> 100,0 -> 0,5 -> 25,5 -> ...
return ...
}
I used IntStream
a lot map
, filter
and so on, but it is much more difficult than anything I have ever tasted. I have no idea how I would do something like this. Can anyone point me in the right direction?
source to share
You can use nested IntStream
to generate each Point
and then flatten the resulting stream:
public Stream<Point> stream(int hstep, int vstep) {
return IntStream.range(0, height / vstep)
.mapToObj(y -> IntStream.range(0, width / hstep)
.mapToObj(x -> new Point(start.x + x * hstep, start.y + y * vstep)))
.flatMap(Function.identity());
}
source to share
You can use iterate(...)
with limit(...)
to generate x
and y
. Then you concatenate both streams and create Point
with flatMap(...)
andmap(...)
public Stream<Point> stream(int hstep, int vstep) {
return Stream.iterate(this.start.x, s-> s + hstep).
limit(this.width / hstep).
flatMap(x-> Stream.iterate(this.start.y, s-> s + vstep).
limit(this.height / vstep).map(y-> new Point(x, y)));
}
source to share
Here's one way to do it.
import java.util.function.Supplier;
import java.util.stream.Stream;
public class Rectangle
{
public int width, height;
public Point start;
public Rectangle(Point start, int width, int height)
{
this.start = start;
this.width = width;
this.height = height;
}
public Stream<Point> stream(int hstep, int vstep)
{
int hSteps = 1 + ((width - 1) / hstep);
int vSteps = 1 + ((height - 1) / vstep);
int numPoints = hSteps * vSteps;
return Stream.generate(new Supplier<Point>()
{
int origStartX = start.x;
int origWidth = width;
int x = start.x;
int y = start.y;
@Override
public Point get()
{
Point pt = new Point(x, y);
x += hstep;
if (x >= origWidth)
{
x = origStartX;
y += vstep;
}
return pt;
}
}).limit(numPoints);
}
public static void main(String[] args)
{
Rectangle r = new Rectangle(new Point(0, 0), 100, 100);
Stream<Point> s = r.stream(25, 5);
s.forEach(System.out::println);
}
}
public class Point
{
public int x, y;
public Point(int x, int y)
{
this.x = x;
this.y = y;
}
public String toString()
{
return String.format("(%d, %d)", x, y);
}
}
Output:
(0, 0)
(25, 0)
(50, 0)
(75, 0)
(0, 5)
(25, 5)
(50, 5)
(75, 5)
.
.
<snip>
.
.
(0, 90)
(25, 90)
(50, 90)
(75, 90)
(0, 95)
(25, 95)
(50, 95)
(75, 95)
source to share