1
\$\begingroup\$

overview

So I have two lists which have the same size. One is called roadS and the second one is called simTime. My aim is to calculate the difference between two indexes which lie next to each other and divide them with the difference of the other list. On the picture above you see what I mean.

This is my current function:

public List<Double> getSpeedS(List<Double> simTime, List<Double> roadS){
    List<Double>  speedS = new ArrayList<>();
    for(int idx = 1; idx < roadS.size();idx++){
        double curSpeedS = (roadS.get(idx)-roadS.get(idx-1))/(simTime.get(idx)-simTime.get(idx-1));
        speedS.add(curSpeedS);
    } 
    return speedS;
}

Now although the function is quite short, I aim to find a better or faster solution.

For eg. in phyton you could you pantas library and do this:

player.df['speedS'] = player.df.roadS.diff().shift(-1) / player.df.simTime.diff().shift(-1)     

My aim is to solve this problem more efficient. Does Java or another library maybe provide such functions where I can for calculate the differences

\$\endgroup\$
  • \$\begingroup\$ To increase efficiency of adding elements to the result, allocate it with the proper size, here new List<Double> speedS = ArrayList<>(simTime.size() -1); \$\endgroup\$ – Gregor Ophey Aug 23 '18 at 10:41
1
\$\begingroup\$

Your implementation is good and easy to understand.

When using List<Double> for input data, be sure to use an efficient implementation. Otherwise you could get really bad read performance. E.g., when you access elements by index, ArrayList<Double> will be much faster than LinkedList<Double> (\$O(n)\$ vs. \$O(n^2)\$ for your getSpeedS).

If you must support arbitrary types of List<Double> you would probably better off when you use Iterators instead of element access by index.

If you use an ArrayList and know its final size in advance, always construct it with the capacity needed (new ArrayList<>(size)). This avoids reallocation and copying of the internal array that holds the elements while adding elements.

If you need maximum performance, then use arrays (double[]) instead of lists. For large data sets they can speed up the creation of the input in-memory objects by factors greater than two. Additionally they may give you a significant advantage in read performance due to better utilization of processor caches compared to list implementations.

\$\endgroup\$
0
\$\begingroup\$

To simplify speed collection creation logic you can replace actual values in roadS and simTime with the corresponding differences, e.g.:

roadS = {2, 0, 2, 1}
simTime= {3, 1, 1, 1}

Then you can use one of the examples provided here.
For example in Java 8:

double[] roadS = {2, 0, 2, 1};
double[] simTime = {3, 1, 1, 1};

double[] c = IntStream.range(0, roadS.length)
      .mapToDouble(i -> roadS[i] / simTime[i])
      .toArray();
\$\endgroup\$
  • \$\begingroup\$ range does not exist for DoubleStream \$\endgroup\$ – plshm Aug 23 '18 at 9:23
  • 1
    \$\begingroup\$ That should probably be IntStream and mapToDouble \$\endgroup\$ – mtj Aug 23 '18 at 9:58
  • \$\begingroup\$ @mtj, thanks for your contribution, edited my answer :) \$\endgroup\$ – Alexey Andronov Aug 23 '18 at 10:04
0
\$\begingroup\$

IMO you code is very clear and therefore easy to understand.

You're comparing the Java code to a Python code which is shorter. But the Python code is using two methods: diff and shift. They provide functionality which you wrote in Java by yourself.

If you're aiming to have a shorter getSpeedS function you can also define a diff function in Java:

protected double diff(List<Double> simTime, List<Double> roadS, int idx) {
    return (roadS.get(idx) - roadS.get(idx - 1)) / (simTime.get(idx) - simTime.get(idx - 1));
}

Using the Stream-API you can implement getSpeedS like this:

public List<Double> getSpeedS(List<Double> simTime, List<Double> roadS) {
    return IntStream.range(0, simTime.size())
            .mapToDouble(idx -> diff(simTime, roadS, idx))
            .boxed()
            .collect(Collectors.toList());
}

And if you write it all in one line ...

public List<Double> getSpeedS(List<Double> simTime, List<Double> roadS) {
    return IntStream.range(0, simTime.size()).mapToDouble(idx -> diff(simTime, roadS, idx)).boxed().collect(Collectors.toList());

}

it's not much longer than the Python code. But writing it all in one line is harder to debug. Therefore I prefer the previous version.

Otherwise you could also implement a DoubleList which provides like the Python collection a diff and a shift function.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.