'Reduce custom object using RxJava

I'm using RxJava, I have a list of Point and i want to calculate the distance between each point and get the sum.

The point class look like this

public class Point {
    public double x;
    public double y;
}

So i need to map and reduce at same time, but i didn't found a solution.

public Observable<Double> totalDistance(Observable<List<Point>> obs) {
 return obs.reduceMap(new ArrayList<Integer>, (list, pointA, pointB) -> distance(pointA, pointB)). ?
}

What its the most efficient way to do it (or at least a solution that works) ? Which operator should i use ?

To give a more concrete example, here is what I have and what I want:

Point a (45, 32)
Point b (56, 75)
Point c (44, 53)
Point d (42, 54)
Point e (42, 55)

a to b = 10m
b to c = 15m
c to d = 25m
d to e = 10m

Result = 60m

In reality my points are GPS positions and I use the haversine formula to calculate the distance between two positions.

I use observables because the list of points to be calculated is updated sometime. In fact every x points the user has reached, I have an instruction to send. After sending the instruction, a new list of points until the next instruction is emit.



Solution 1:[1]

You can use the map() method to convert the values of an Observable<List<Point>> to values for an Observable<Double>. The code can look like this:

public static void main(String[] args) throws Exception {
    Point a = new Point(45, 32);
    Point b = new Point(56, 75);
    Point c = new Point(44, 53);
    Point d = new Point(42, 54);
    Point e = new Point(42, 55);
    
    List<Point> points = new ArrayList<Point>();
    points.add(a);
    points.add(b);
    points.add(c);
    points.add(d);
    points.add(e);
    
    Subject<List<Point>> subjectOfListOfPoints = PublishSubject.create();
    
    Observable<List<Point>> observable = subjectOfListOfPoints;
    
    Observable<Double> doubleObservable = observable.map(it -> { 
        return calculateSumOfDistances(it); });
    
    doubleObservable.subscribe(it -> {
        System.out.println("The sum is: "+it);
    });
    
    subjectOfListOfPoints.onNext(points);
}

private static double calculateSumOfDistances(List<Point> points) {
    List<Double> distances = new ArrayList<Double>();
    for (int i=0; i<points.size()-1; i++) {
        double distance = distance(points.get(i), points.get(i+1));
        System.out.println("Distance is: "+distance);
        distances.add(distance);
    }
    double sum = 0;
    for (Double d: distances) {
        sum += d;
    }
    return sum;
}

private static double distance(Point a, Point b) {
    return Math.sqrt(Math.pow(a.x - b.x, 2) + Math.pow(a.y - b.y, 2));
}

This will create the following output:

Distance is: 44.384682042344295
Distance is: 25.059928172283335
Distance is: 2.23606797749979
Distance is: 1.0
The sum is: 72.68067819212742

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Progman