1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    * 
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   * 
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.commons.math.stat.descriptive;
18  
19  import java.io.Serializable;
20  import java.util.ArrayList;
21  import java.util.List;
22  
23  import org.apache.commons.math.MathException;
24  import org.apache.commons.math.stat.descriptive.UnivariateStatistic;
25  import org.apache.commons.math.stat.descriptive.DescriptiveStatistics;
26  import org.apache.commons.math.util.DefaultTransformer;
27  import org.apache.commons.math.util.NumberTransformer;
28  
29  /**
30   * @version $Revision: 762087 $ $Date: 2009-04-05 10:20:18 -0400 (Sun, 05 Apr 2009) $
31   */
32  public class ListUnivariateImpl extends DescriptiveStatistics implements Serializable {
33  
34      /** Serializable version identifier */
35      private static final long serialVersionUID = -8837442489133392138L;
36      
37      /**
38       * Holds a reference to a list - GENERICs are going to make
39       * our lives easier here as we could only accept List<Number>
40       */
41      protected List<Object> list;
42  
43      /** Number Transformer maps Objects to Number for us. */
44      protected NumberTransformer transformer;
45  
46      /**
47       * No argument Constructor
48       */
49      public ListUnivariateImpl(){
50          this(new ArrayList<Object>());
51      }
52      
53      /**
54       * Construct a ListUnivariate with a specific List.
55       * @param list The list that will back this DescriptiveStatistics
56       */
57      public ListUnivariateImpl(List<Object> list) {
58          this(list, new DefaultTransformer());
59      }
60      
61      /**
62       * Construct a ListUnivariate with a specific List.
63       * @param list The list that will back this DescriptiveStatistics
64       * @param transformer the number transformer used to convert the list items.
65       */
66      public ListUnivariateImpl(List<Object> list, NumberTransformer transformer) {
67          super();
68          this.list = list;
69          this.transformer = transformer;
70      }
71  
72      /** {@inheritDoc} */
73      @Override
74      public double[] getValues() {
75  
76          int length = list.size();
77  
78          // If the window size is not INFINITE_WINDOW AND
79          // the current list is larger that the window size, we need to
80          // take into account only the last n elements of the list
81          // as definied by windowSize
82  
83          if (windowSize != DescriptiveStatistics.INFINITE_WINDOW &&
84              windowSize < list.size())
85          {
86              length = list.size() - Math.max(0, list.size() - windowSize);
87          }
88  
89          // Create an array to hold all values
90          double[] copiedArray = new double[length];
91  
92          for (int i = 0; i < copiedArray.length; i++) {
93              copiedArray[i] = getElement(i);
94          }
95          return copiedArray;
96      }
97  
98      /** {@inheritDoc} */
99      @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 }