Java 8: Find index of minimum value from a List

前端 未结 4 1681
北荒
北荒 2021-02-01 23:50

Say I have a list with elements (34, 11, 98, 56, 43).

Using Java 8 streams, how do I find the index of the minimum element of the list (e.g. 1 in this case)

4条回答
  •  -上瘾入骨i
    2021-02-02 00:13

    Since this is for learning purposes, let's try to find a solution that doesn't just somehow use a stream, but actually works on the stream of our list. We also don't want to assume random access.

    So, there are two ways to get a non-trivial result out of a stream: collect and reduce. Here is a solution that uses a collector:

    class Minimum {
        int index = -1; 
        int range = 0;
        int value;
    
        public void accept(int value) {
            if (range == 0 || value < this.value) {
                index = range;
                this.value = value;
            }
            range++;
        }
    
        public Minimum combine(Minimum other) {
            if (value > other.value) {
                index = range + other.index;
                value = other.value;
            }
            range += other.range;
            return this;
        }
    
        public int getIndex() {
            return index;
        }
    }
    
    static Collector MIN_INDEX = new Collector() {
            @Override
            public Supplier supplier() {
                return Minimum::new;
            }
            @Override
            public BiConsumer accumulator() {
                return Minimum::accept;
            }
            @Override
            public BinaryOperator combiner() {
               return Minimum::combine;
            }
            @Override
            public Function finisher() {
                return Minimum::getIndex;
            }
            @Override
            public Set characteristics() {
                return Collections.emptySet();
            }
        };
    

    Writing a collectors creates an annoying amount of code, but it can be easily generalized to support any comparable value. Also, calling the collector looks very idiomatic:

    List list = Arrays.asList(4,3,7,1,5,2,9);
    int minIndex = list.stream().collect(MIN_INDEX);
    

    If we change the accept and combine methods to always return a new Minimum instance (ie. if we make Minimum immutable), we can also use reduce:

    int minIndex = list.stream().reduce(new Minimum(), Minimum::accept, Minimum::combine).getIndex();
    

    I sense large potential for parallelization in this one.

提交回复
热议问题