001/* 002 * Units of Measurement Implementation for Java SE 003 * Copyright (c) 2005-2017, Jean-Marie Dautelle, Werner Keil, V2COM. 004 * 005 * All rights reserved. 006 * 007 * Redistribution and use in source and binary forms, with or without modification, 008 * are permitted provided that the following conditions are met: 009 * 010 * 1. Redistributions of source code must retain the above copyright notice, 011 * this list of conditions and the following disclaimer. 012 * 013 * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions 014 * and the following disclaimer in the documentation and/or other materials provided with the distribution. 015 * 016 * 3. Neither the name of JSR-363 nor the names of its contributors may be used to endorse or promote products 017 * derived from this software without specific prior written permission. 018 * 019 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 020 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 021 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 022 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 023 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 024 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 025 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 026 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 027 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 028 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 029 */ 030package tec.uom.se.function; 031 032import java.util.Objects; 033import java.util.function.BinaryOperator; 034 035import javax.measure.Quantity; 036import javax.measure.Unit; 037 038import tec.uom.se.quantity.Quantities; 039 040/** 041 * @author Otavio 042 * @author Werner 043 * @version 1.0 044 * @since 1.0 045 * @param <Q> 046 */ 047public class QuantitySummaryStatistics<Q extends Quantity<Q>> { 048 049 private final Quantity<Q> empty; 050 051 private long count; 052 053 private Quantity<Q> min; 054 055 private Quantity<Q> max; 056 057 private Quantity<Q> sum; 058 059 private Quantity<Q> average; 060 061 private final BinaryOperator<Quantity<Q>> minFunctions = QuantityFunctions.min(); 062 063 private final BinaryOperator<Quantity<Q>> maxFunctions = QuantityFunctions.max(); 064 065 /** 066 * Creates a new instance, targeting the given {@link javax.measure.Unit}. 067 * 068 * @param unit 069 * the target unit, not null. 070 */ 071 QuantitySummaryStatistics(Unit<Q> unit) { 072 empty = Quantities.getQuantity(0, unit); 073 setQuantity(empty); 074 } 075 076 /** 077 * Records another value into the summary information. 078 * 079 * @param quantity 080 * the input quantity value to be added, not null. 081 */ 082 public void accept(Quantity<Q> quantity) { 083 084 Objects.requireNonNull(quantity); 085 086 if (isEmpty()) { 087 setQuantity(quantity.to(empty.getUnit())); 088 count++; 089 } else { 090 doSummary(quantity.to(empty.getUnit())); 091 } 092 } 093 094 /** 095 * Combines the state of another {@code QuantitySummaryStatistics} into this one. 096 * 097 * @param quantitySummary 098 * another {@code QuantitySummaryStatistics}, not null. 099 */ 100 public QuantitySummaryStatistics<Q> combine(QuantitySummaryStatistics<Q> quantitySummary) { 101 Objects.requireNonNull(quantitySummary); 102 103 if (!equals(quantitySummary)) { 104 return this; 105 } 106 107 min = minFunctions.apply(min, quantitySummary.min.to(empty.getUnit())); 108 max = maxFunctions.apply(max, quantitySummary.max.to(empty.getUnit())); 109 sum = sum.add(quantitySummary.sum); 110 count += quantitySummary.count; 111 average = sum.divide(count); 112 return this; 113 } 114 115 private void doSummary(Quantity<Q> moneraty) { 116 min = minFunctions.apply(min, moneraty); 117 max = maxFunctions.apply(max, moneraty); 118 sum = sum.add(moneraty); 119 average = sum.divide(++count); 120 } 121 122 private boolean isEmpty() { 123 return count == 0; 124 } 125 126 private void setQuantity(Quantity<Q> quantity) { 127 min = quantity; 128 max = quantity; 129 sum = quantity; 130 average = quantity; 131 } 132 133 /** 134 * Get the number of items added to this summary instance. 135 * 136 * @return the number of summarized items, >= 0. 137 */ 138 public long getCount() { 139 return count; 140 } 141 142 /** 143 * Get the minimal quantity found within this summary. 144 * 145 * @return the minimal quantity 146 */ 147 public Quantity<Q> getMin() { 148 return min; 149 } 150 151 /** 152 * Get the minimal quantity found within this summary converted to unit 153 * 154 * @param unit 155 * to convert 156 * @return the minimal quantity converted to this unit 157 */ 158 public Quantity<Q> getMin(Unit<Q> unit) { 159 return min.to(unit); 160 } 161 162 /** 163 * Get the maximal amount found within this summary. 164 * 165 * @return the maximal quantity 166 */ 167 public Quantity<Q> getMax() { 168 return max; 169 } 170 171 /** 172 * Get the maximal amount found within this summary converted to unit 173 * 174 * @param unit 175 * to convert 176 * @return the maximal quantity converted to this unit 177 */ 178 public Quantity<Q> getMax(Unit<Q> unit) { 179 return max.to(unit); 180 } 181 182 /** 183 * Get the sum of all amounts within this summary. 184 * 185 * @return the total amount 186 */ 187 public Quantity<Q> getSum() { 188 return sum; 189 } 190 191 /** 192 * Get the sum of all amounts within this summary converted to unit 193 * 194 * @param unit 195 * to convert 196 * @return the total amount converted to this unit 197 */ 198 public Quantity<Q> getSum(Unit<Q> unit) { 199 return sum.to(unit); 200 } 201 202 /** 203 * Get the quantity average of all amounts added. 204 * 205 * @return the quantity average quantity 206 */ 207 public Quantity<Q> getAverage() { 208 return average; 209 } 210 211 /** 212 * Get the quantity average of all amounts added converted to unit 213 * 214 * @param unit 215 * to convert 216 * @return the average quantity converted to this unit 217 */ 218 public Quantity<Q> getAverage(Unit<Q> unit) { 219 return average.to(unit); 220 } 221 222 /** 223 * convert the summary to this unit measure 224 * 225 * @param unit 226 * to convert the summary 227 * @return the summary converted to this unit 228 */ 229 public QuantitySummaryStatistics<Q> to(Unit<Q> unit) { 230 QuantitySummaryStatistics<Q> summary = new QuantitySummaryStatistics<>(unit); 231 summary.average = average.to(unit); 232 summary.count = count; 233 summary.max = max.to(unit); 234 summary.min = min.to(unit); 235 summary.sum = sum.to(unit); 236 return summary; 237 } 238 239 /** 240 * will equals when the unit were equals 241 */ 242 @Override 243 public boolean equals(Object obj) { 244 if (QuantitySummaryStatistics.class.isInstance(obj)) { 245 @SuppressWarnings("rawtypes") 246 QuantitySummaryStatistics other = QuantitySummaryStatistics.class.cast(obj); 247 return Objects.equals(empty.getUnit(), other.empty.getUnit()); 248 } 249 return false; 250 } 251 252 @Override 253 public int hashCode() { 254 return empty.getUnit().hashCode(); 255 } 256 257 @Override 258 public String toString() { 259 final StringBuilder sb = new StringBuilder(); 260 sb.append("[currency: ").append(empty.getUnit()).append(","); 261 sb.append("count:").append(count).append(","); 262 sb.append("min:").append(min).append(","); 263 sb.append("max:").append(max).append(","); 264 sb.append("sum:").append(sum).append(","); 265 sb.append("average:").append(average).append("]"); 266 return sb.toString(); 267 } 268}