001    /*--------------------------------------------------------------------------+
002    $Id: MedianAggregator.java 29788 2010-08-19 08:46:02Z juergens $
003    |                                                                          |
004    | Copyright 2005-2010 Technische Universitaet Muenchen                     |
005    |                                                                          |
006    | Licensed under the Apache License, Version 2.0 (the "License");          |
007    | you may not use this file except in compliance with the License.         |
008    | You may obtain a copy of the License at                                  |
009    |                                                                          |
010    |    http://www.apache.org/licenses/LICENSE-2.0                            |
011    |                                                                          |
012    | Unless required by applicable law or agreed to in writing, software      |
013    | distributed under the License is distributed on an "AS IS" BASIS,        |
014    | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
015    | See the License for the specific language governing permissions and      |
016    | limitations under the License.                                           |
017    +--------------------------------------------------------------------------*/
018    package edu.tum.cs.commons.math;
019    
020    import java.util.ArrayList;
021    import java.util.Collection;
022    import java.util.Collections;
023    
024    /**
025     * Median aggregator. Note that for an even number of elements this aggregator
026     * returns the mean value of both middle elements.
027     * 
028     * @author deissenb
029     * @author $Author: juergens $
030     * @version $Rev: 29788 $
031     * @levd.rating GREEN Hash: 263069760E186DA03CC4463A773263DD
032     */
033    public class MedianAggregator implements IAggregator {
034    
035            /**
036             * Aggregates by finding the median.
037             * 
038             * @return {@link Double#NaN} for empty input collection
039             */
040            @Override
041            public double aggregate(Collection<? extends Number> values) {
042                    if (values.isEmpty()) {
043                            return Double.NaN;
044                    }
045    
046                    ArrayList<Double> doubleValues = new ArrayList<Double>();
047    
048                    for (Number value : values) {
049                            doubleValues.add(value.doubleValue());
050                    }
051    
052                    Collections.sort(doubleValues);
053    
054                    // odd number of elements
055                    if (doubleValues.size() % 2 == 1) {
056                            int medianIndex = (int) Math.ceil(doubleValues.size() / 2);
057                            return doubleValues.get(medianIndex);
058                    }
059    
060                    // even number of elements
061                    int lowerMedianIndex = doubleValues.size() / 2 - 1;
062                    double lowerMedian = doubleValues.get(lowerMedianIndex);
063                    double upperMedian = doubleValues.get(lowerMedianIndex + 1);
064    
065                    return (lowerMedian + upperMedian) / 2;
066            }
067    
068            /** Returns {@link Double#NaN}. */
069            @Override
070            public double getNeutralElement() {
071                    return Double.NaN;
072            }
073    }