001    /*
002     * Licensed to the Apache Software Foundation (ASF) under one or more
003     * contributor license agreements.  See the NOTICE file distributed with
004     * this work for additional information regarding copyright ownership.
005     * The ASF licenses this file to You under the Apache License, Version 2.0
006     * (the "License"); you may not use this file except in compliance with
007     * the License.  You may obtain a copy of the License at
008     * 
009     *      http://www.apache.org/licenses/LICENSE-2.0
010     * 
011     * Unless required by applicable law or agreed to in writing, software
012     * distributed under the License is distributed on an "AS IS" BASIS,
013     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014     * See the License for the specific language governing permissions and
015     * limitations under the License.
016     */
017    package org.apache.commons.math.stat.descriptive;
018    
019    import java.io.Serializable;
020    import java.util.ArrayList;
021    import java.util.List;
022    
023    import org.apache.commons.math.MathException;
024    import org.apache.commons.math.stat.descriptive.UnivariateStatistic;
025    import org.apache.commons.math.stat.descriptive.DescriptiveStatistics;
026    import org.apache.commons.math.util.DefaultTransformer;
027    import org.apache.commons.math.util.NumberTransformer;
028    
029    /**
030     * @version $Revision: 762087 $ $Date: 2009-04-05 10:20:18 -0400 (Sun, 05 Apr 2009) $
031     */
032    public class ListUnivariateImpl extends DescriptiveStatistics implements Serializable {
033    
034        /** Serializable version identifier */
035        private static final long serialVersionUID = -8837442489133392138L;
036        
037        /**
038         * Holds a reference to a list - GENERICs are going to make
039         * our lives easier here as we could only accept List<Number>
040         */
041        protected List<Object> list;
042    
043        /** Number Transformer maps Objects to Number for us. */
044        protected NumberTransformer transformer;
045    
046        /**
047         * No argument Constructor
048         */
049        public ListUnivariateImpl(){
050            this(new ArrayList<Object>());
051        }
052        
053        /**
054         * Construct a ListUnivariate with a specific List.
055         * @param list The list that will back this DescriptiveStatistics
056         */
057        public ListUnivariateImpl(List<Object> list) {
058            this(list, new DefaultTransformer());
059        }
060        
061        /**
062         * Construct a ListUnivariate with a specific List.
063         * @param list The list that will back this DescriptiveStatistics
064         * @param transformer the number transformer used to convert the list items.
065         */
066        public ListUnivariateImpl(List<Object> list, NumberTransformer transformer) {
067            super();
068            this.list = list;
069            this.transformer = transformer;
070        }
071    
072        /** {@inheritDoc} */
073        @Override
074        public double[] getValues() {
075    
076            int length = list.size();
077    
078            // If the window size is not INFINITE_WINDOW AND
079            // the current list is larger that the window size, we need to
080            // take into account only the last n elements of the list
081            // as definied by windowSize
082    
083            if (windowSize != DescriptiveStatistics.INFINITE_WINDOW &&
084                windowSize < list.size())
085            {
086                length = list.size() - Math.max(0, list.size() - windowSize);
087            }
088    
089            // Create an array to hold all values
090            double[] copiedArray = new double[length];
091    
092            for (int i = 0; i < copiedArray.length; i++) {
093                copiedArray[i] = getElement(i);
094            }
095            return copiedArray;
096        }
097    
098        /** {@inheritDoc} */
099        @Override
100        public double getElement(int index) {
101    
102            double value = Double.NaN;
103    
104            int calcIndex = index;
105    
106            if (windowSize != DescriptiveStatistics.INFINITE_WINDOW &&
107                windowSize < list.size())
108            {
109                calcIndex = (list.size() - windowSize) + index;
110            }
111    
112            
113            try {
114                value = transformer.transform(list.get(calcIndex));
115            } catch (MathException e) {
116                e.printStackTrace();
117            }
118            
119            return value;
120        }
121    
122        /** {@inheritDoc} */
123        @Override
124        public long getN() {
125            int n = 0;
126    
127            if (windowSize != DescriptiveStatistics.INFINITE_WINDOW) {
128                if (list.size() > windowSize) {
129                    n = windowSize;
130                } else {
131                    n = list.size();
132                }
133            } else {
134                n = list.size();
135            }
136            return n;
137        }
138    
139        /** {@inheritDoc} */
140        @Override
141        public void addValue(double v) {
142            list.add(Double.valueOf(v));
143        }
144        
145        /**
146         * Adds an object to this list. 
147         * @param o Object to add to the list
148         */
149        public void addObject(Object o) {
150            list.add(o);
151        }
152    
153        /**
154         * Clears all statistics.
155         * <p>
156         * <strong>N.B.: </strong> This method has the side effect of clearing the underlying list.
157         */
158        @Override
159        public void clear() {
160            list.clear();
161        }
162        
163        /**
164         * Apply the given statistic to this univariate collection.
165         * @param stat the statistic to apply
166         * @return the computed value of the statistic.
167         */
168        @Override
169        public double apply(UnivariateStatistic stat) {
170            double[] v = this.getValues();
171    
172            if (v != null) {
173                return stat.evaluate(v, 0, v.length);
174            }
175            return Double.NaN;
176        }
177        
178        /**
179         * Access the number transformer.
180         * @return the number transformer.
181         */
182        public NumberTransformer getTransformer() {
183            return transformer;
184        }
185    
186        /**
187         * Modify the number transformer.
188         * @param transformer the new number transformer.
189         */
190        public void setTransformer(NumberTransformer transformer) {
191            this.transformer = transformer;
192        }
193        
194        /** {@inheritDoc} */
195        @Override
196        public synchronized void setWindowSize(int windowSize) {
197            this.windowSize = windowSize;
198            //Discard elements from the front of the list if the windowSize is less than 
199            // the size of the list.
200            int extra = list.size() - windowSize;
201            for (int i = 0; i < extra; i++) {
202                list.remove(0);
203            }
204        }
205    
206        /** {@inheritDoc} */
207        @Override
208        public synchronized int getWindowSize() {
209            return windowSize;
210        }
211    
212    }