4

How to sort a collection using comparator and a parameter in Java 8?

Here is a piece of code:

    List<Point> sortedNeurons = neurons.parallelStream()
        .sorted((n1, n2) -> Double.compare(
            n1.getEuclideanDistanceFrom(inputVector),
            n2.getEuclideanDistanceFrom(inputVector)))
        .collect(Collectors.toList());

You are given a parameter inputVector that can be passed to a function that returns a primitive double value. If applied to an element of the collection, it returns some number. I want the collection to be ordered by this value. Something like: select id from neurons order by getEuclideanDistanceFrom(inputVector, id);

There are three problems here:

  1. nx.getEuclideanDistanceFrom(inputVector) gets repeated twice.
  2. I would like to use natural ordering of a double type, without declaring it, just like in an SQL query, when using order by clause.
  3. Perhaps n1, n2 -> n1, n2 could be substituted with a double colon :: notation.

P.S. I have a strong feeling that it can be fixed using something like bifunction or biconsumer... but couldn't figure it out...

3 Answers 3

8

Maybe you can do it with Comparator#comparingDouble:

List<Point> sortedNeurons = neurons.parallelStream()
    .sorted(Comparator.comparingDouble(p -> p.getEuclideanDistanceFrom(inputVector)))
    .collect(Collectors.toList());
Sign up to request clarification or add additional context in comments.

Comments

2

This looks good. I made it even better:

List<Point> sortedNeurons = neurons.parallelStream()
    .sorted(Comparator.comparingDouble(inputVector::getEuclideanDistanceFrom))
    .collect(Collectors.toList());

and then I realized, you can make it even shorter:

List<Point> sortedNeurons =
neurons.sort(Comparator.comparingDouble(inputVector::getEuclideanDistanceFrom));

Apparently streams are not good for sorting things...

2 Comments

Not sure what you mean by "streams are not good for sorting things." The first snippet seems quite reasonable. If neurons is a list, the second snippet doesn't work. The List.sort() method sorts the list in place and returns void.
you are right. This makes all I need. From 5 lines of code I got to 1! It just cannot be better neurons.sort(Comparator.comparingDouble(inputVector::getEuclideanDistanceFrom));
0

I also found a way to extract the comparator that can be reused:

public interface Functional<T> {
    public int compareByEuclideanDistance(T o1, T o2);
}

public class Point implements Functional<Point> {
    @Override
    public int compareByEuclideanDistance(Point o1, Point o2) {
        return Double.compare(this.getEuclideanDistanceFrom(o1),
            this.getEuclideanDistanceFrom(o2));
    }
}

Now you can make any call such as:

neurons.parallelStream()
    .sorted(input::compareByEuclideanDistance)
    .collect(Collectors.toList());

or

neurons.parallelStream().min(input::compareByEuclideanDistance).get();

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.