001/* 002 * Units of Measurement Reference Implementation 003 * Copyright (c) 2005-2020, Units of Measurement project. 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-385, Indriya nor the names of their 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 tech.units.indriya.function; 031 032import static tech.uom.lib.common.function.QuantityFunctions.*; 033 034import java.util.Objects; 035import java.util.function.BinaryOperator; 036 037import javax.measure.Quantity; 038import javax.measure.Unit; 039 040import tech.units.indriya.quantity.Quantities; 041 042/** 043 * @author Otavio 044 * @author Werner 045 * @version 1.2 046 * @since 1.0 047 * @param <Q> 048 */ 049public class QuantitySummaryStatistics<Q extends Quantity<Q>> { 050 051 private final Quantity<Q> empty; 052 053 private long count; 054 055 private Quantity<Q> min; 056 057 private Quantity<Q> max; 058 059 private Quantity<Q> sum; 060 061 private Quantity<Q> average; 062 063 private final BinaryOperator<Quantity<Q>> minFunctions = min(); 064 065 private final BinaryOperator<Quantity<Q>> maxFunctions = max(); 066 067 /** 068 * Creates a new instance, targeting the given {@link javax.measure.Unit}. 069 * 070 * @param unit 071 * the target unit, not null. 072 */ 073 QuantitySummaryStatistics(Unit<Q> unit) { 074 empty = Quantities.getQuantity(0, unit); 075 setQuantity(empty); 076 } 077 078 /** 079 * Records another value into the summary information. 080 * 081 * @param quantity 082 * the input quantity value to be added, not null. 083 */ 084 public void accept(Quantity<Q> quantity) { 085 086 Objects.requireNonNull(quantity); 087 088 if (isEmpty()) { 089 setQuantity(quantity.to(empty.getUnit())); 090 count++; 091 } else { 092 doSummary(quantity.to(empty.getUnit())); 093 } 094 } 095 096 /** 097 * Combines the state of another {@code QuantitySummaryStatistics} into this one. 098 * 099 * @param quantitySummary 100 * another {@code QuantitySummaryStatistics}, not null. 101 */ 102 public QuantitySummaryStatistics<Q> combine(QuantitySummaryStatistics<Q> quantitySummary) { 103 Objects.requireNonNull(quantitySummary); 104 105 if (!equals(quantitySummary)) { 106 return this; 107 } 108 109 min = minFunctions.apply(min, quantitySummary.min.to(empty.getUnit())); 110 max = maxFunctions.apply(max, quantitySummary.max.to(empty.getUnit())); 111 sum = sum.add(quantitySummary.sum); 112 count += quantitySummary.count; 113 average = sum.divide(count); 114 return this; 115 } 116 117 private void doSummary(Quantity<Q> moneraty) { 118 min = minFunctions.apply(min, moneraty); 119 max = maxFunctions.apply(max, moneraty); 120 sum = sum.add(moneraty); 121 average = sum.divide(++count); 122 } 123 124 private boolean isEmpty() { 125 return count == 0; 126 } 127 128 private void setQuantity(Quantity<Q> quantity) { 129 min = quantity; 130 max = quantity; 131 sum = quantity; 132 average = quantity; 133 } 134 135 /** 136 * Get the number of items added to this summary instance. 137 * 138 * @return the number of summarized items, >= 0. 139 */ 140 public long getCount() { 141 return count; 142 } 143 144 /** 145 * Get the minimal quantity found within this summary. 146 * 147 * @return the minimal quantity 148 */ 149 public Quantity<Q> getMin() { 150 return min; 151 } 152 153 /** 154 * Get the minimal quantity found within this summary converted to unit 155 * 156 * @param unit 157 * to convert 158 * @return the minimal quantity converted to this unit 159 */ 160 public Quantity<Q> getMin(Unit<Q> unit) { 161 return min.to(unit); 162 } 163 164 /** 165 * Get the maximal amount found within this summary. 166 * 167 * @return the maximal quantity 168 */ 169 public Quantity<Q> getMax() { 170 return max; 171 } 172 173 /** 174 * Get the maximal amount found within this summary converted to unit 175 * 176 * @param unit 177 * to convert 178 * @return the maximal quantity converted to this unit 179 */ 180 public Quantity<Q> getMax(Unit<Q> unit) { 181 return max.to(unit); 182 } 183 184 /** 185 * Get the sum of all amounts within this summary. 186 * 187 * @return the total amount 188 */ 189 public Quantity<Q> getSum() { 190 return sum; 191 } 192 193 /** 194 * Get the sum of all amounts within this summary converted to unit 195 * 196 * @param unit 197 * to convert 198 * @return the total amount converted to this unit 199 */ 200 public Quantity<Q> getSum(Unit<Q> unit) { 201 return sum.to(unit); 202 } 203 204 /** 205 * Get the quantity average of all amounts added. 206 * 207 * @return the quantity average quantity 208 */ 209 public Quantity<Q> getAverage() { 210 return average; 211 } 212 213 /** 214 * Get the quantity average of all amounts added converted to unit 215 * 216 * @param unit 217 * to convert 218 * @return the average quantity converted to this unit 219 */ 220 public Quantity<Q> getAverage(Unit<Q> unit) { 221 return average.to(unit); 222 } 223 224 /** 225 * convert the summary to this unit measure 226 * 227 * @param unit 228 * to convert the summary 229 * @return the summary converted to this unit 230 */ 231 public QuantitySummaryStatistics<Q> to(Unit<Q> unit) { 232 QuantitySummaryStatistics<Q> summary = new QuantitySummaryStatistics<>(unit); 233 summary.average = average.to(unit); 234 summary.count = count; 235 summary.max = max.to(unit); 236 summary.min = min.to(unit); 237 summary.sum = sum.to(unit); 238 return summary; 239 } 240 241 /** 242 * will equals when the unit were equals 243 */ 244 @Override 245 public boolean equals(Object obj) { 246 if (QuantitySummaryStatistics.class.isInstance(obj)) { 247 @SuppressWarnings("rawtypes") 248 QuantitySummaryStatistics other = QuantitySummaryStatistics.class.cast(obj); 249 return Objects.equals(empty.getUnit(), other.empty.getUnit()); 250 } 251 return false; 252 } 253 254 @Override 255 public int hashCode() { 256 return empty.getUnit().hashCode(); 257 } 258 259 @Override 260 public String toString() { 261 final StringBuilder sb = new StringBuilder(); 262 sb.append("[unit: ").append(empty.getUnit()).append(","); 263 sb.append("count:").append(count).append(","); 264 sb.append("min:").append(min).append(","); 265 sb.append("max:").append(max).append(","); 266 sb.append("sum:").append(sum).append(","); 267 sb.append("average:").append(average).append("]"); 268 return sb.toString(); 269 } 270}