简体   繁体   中英

How to sort a stream by parameter using a comparator in Java 8?

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.

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

Maybe you can do it with Comparator#comparingDouble :

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

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...

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();

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM