001 /*
002 * Java Genetic Algorithm Library (jenetics-4.1.0).
003 * Copyright (c) 2007-2018 Franz Wilhelmstötter
004 *
005 * Licensed under the Apache License, Version 2.0 (the "License");
006 * you may not use this file except in compliance with the License.
007 * 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 * Author:
018 * Franz Wilhelmstötter (franz.wilhelmstoetter@gmail.com)
019 */
020 package io.jenetics.stat;
021
022 import static java.lang.String.format;
023 import static java.util.Objects.requireNonNull;
024
025 import java.util.Comparator;
026 import java.util.Objects;
027 import java.util.function.Consumer;
028 import java.util.stream.Collector;
029
030 /**
031 * This <i>consumer</i> class is used for calculating the min and max value
032 * according to the given {@code Comparator}.
033 * <p>
034 * This class is designed to work with (though does not require) streams. For
035 * example, you can compute minimum and maximum values with:
036 * <pre>{@code
037 * final Stream<Integer> stream = ...
038 * final MinMax<Integer> minMax = stream.collect(
039 * MinMax::of,
040 * MinMax::accept,
041 * MinMax::combine
042 * );
043 * }</pre>
044 *
045 * @implNote
046 * This implementation is not thread safe. However, it is safe to use on a
047 * parallel stream, because the parallel implementation of
048 * {@link java.util.stream.Stream#collect Stream.collect()}provides the
049 * necessary partitioning, isolation, and merging of results for safe and
050 * efficient parallel execution.
051 *
052 * @author <a href="mailto:franz.wilhelmstoetter@gmail.com">Franz Wilhelmstötter</a>
053 * @since 3.0
054 * @version 3.7
055 */
056 public final class MinMax<C> implements Consumer<C> {
057
058 private final Comparator<? super C> _comparator;
059
060 private C _min;
061 private C _max;
062 private long _count = 0L;
063
064 private MinMax(final Comparator<? super C> comparator) {
065 _comparator = requireNonNull(comparator);
066 }
067
068 /**
069 * Accept the element for min-max calculation.
070 *
071 * @param object the element to use for min-max calculation
072 */
073 @Override
074 public void accept(final C object) {
075 _min = min(_comparator, _min, object);
076 _max = max(_comparator, _max, object);
077 ++_count;
078 }
079
080 /**
081 * Combine two {@code MinMax} objects.
082 *
083 * @param other the other {@code MinMax} object to combine
084 * @return {@code this}
085 * @throws java.lang.NullPointerException if the {@code other} object is
086 * {@code null}.
087 */
088 public MinMax<C> combine(final MinMax<C> other) {
089 _min = min(_comparator, _min, other._min);
090 _max = max(_comparator, _max, other._max);
091 _count += other._count;
092
093 return this;
094 }
095
096 /**
097 * Return the current minimal object or {@code null} if no element has been
098 * accepted yet.
099 *
100 * @return the current minimal object
101 */
102 public C getMin() {
103 return _min;
104 }
105
106 /**
107 * Return the current maximal object or {@code null} if no element has been
108 * accepted yet.
109 *
110 * @return the current maximal object
111 */
112 public C getMax() {
113 return _max;
114 }
115
116 /**
117 * Returns the count of values recorded.
118 *
119 * @return the count of recorded values
120 */
121 public long getCount() {
122 return _count;
123 }
124
125 /**
126 * Compares the state of two {@code LongMomentStatistics} objects. This is
127 * a replacement for the {@link #equals(Object)} which is not advisable to
128 * implement for this mutable object. If two object have the same state, it
129 * has still the same state when updated with the same value.
130 * <pre>{@code
131 * final MinMax mm1 = ...;
132 * final MinMax mm2 = ...;
133 *
134 * if (mm1.sameState(mm2)) {
135 * final long value = random.nextInt(1_000_000);
136 * mm1.accept(value);
137 * mm2.accept(value);
138 *
139 * assert mm1.sameState(mm2);
140 * assert mm2.sameState(mm1);
141 * assert mm1.sameState(mm1);
142 * }
143 * }</pre>
144 *
145 * @since 3.7
146 *
147 * @param other the other object for the test
148 * @return {@code true} the {@code this} and the {@code other} objects have
149 * the same state, {@code false} otherwise
150 */
151 public boolean sameState(final MinMax<C> other) {
152 return Objects.equals(_min, other._min) &&
153 Objects.equals(_max, other._max);
154 }
155
156 @Override
157 public String toString() {
158 return format("MinMax[count=%d, min=%s, max=%s]", _count, _min, _max);
159 }
160
161 /* *************************************************************************
162 * Some static helper methods.
163 * ************************************************************************/
164
165 /**
166 * Return the minimum of two values, according the given comparator.
167 * {@code null} values are allowed.
168 *
169 * @param comp the comparator used for determining the min value
170 * @param a the first value to compare
171 * @param b the second value to compare
172 * @param <T> the type of the compared objects
173 * @return the minimum value, or {@code null} if both values are {@code null}.
174 * If only one value is {@code null}, the non {@code null} values is
175 * returned.
176 */
177 public static <T> T
178 min(final Comparator<? super T> comp, final T a, final T b) {
179 return a != null ? b != null ? comp.compare(a, b) <= 0 ? a : b : a : b;
180 }
181
182 /**
183 * Return the maximum of two values, according the given comparator.
184 * {@code null} values are allowed.
185 *
186 * @param comp the comparator used for determining the max value
187 * @param a the first value to compare
188 * @param b the second value to compare
189 * @param <T> the type of the compared objects
190 * @return the maximum value, or {@code null} if both values are {@code null}.
191 * If only one value is {@code null}, the non {@code null} values is
192 * returned.
193 */
194 public static <T> T
195 max(final Comparator<? super T> comp, final T a, final T b) {
196 return a != null ? b != null ? comp.compare(a, b) >= 0 ? a : b : a : b;
197 }
198
199
200 /* *************************************************************************
201 * Some static factory methods.
202 * ************************************************************************/
203
204 /**
205 * Return a {@code Collector} which calculates the minimum and maximum value.
206 * The given {@code comparator} is used for comparing two objects.
207 *
208 * <pre>{@code
209 * final Comparator<SomeObject> comparator = ...
210 * final Stream<SomeObject> stream = ...
211 * final MinMax<SomeObject> moments = stream
212 * .collect(doubleMoments.toMinMax(comparator));
213 * }</pre>
214 *
215 * @param comparator the {@code Comparator} to use
216 * @param <T> the type of the input elements
217 * @return a {@code Collector} implementing the min-max reduction
218 * @throws java.lang.NullPointerException if the given {@code mapper} is
219 * {@code null}
220 */
221 public static <T> Collector<T, ?, MinMax<T>>
222 toMinMax(final Comparator<? super T> comparator) {
223 requireNonNull(comparator);
224 return Collector.of(
225 () -> MinMax.of(comparator),
226 MinMax::accept,
227 MinMax::combine
228 );
229 }
230
231 /**
232 * Return a {@code Collector} which calculates the minimum and maximum value.
233 * The <i>reducing</i> objects must be comparable.
234 *
235 * <pre>{@code
236 * final Stream<SomeObject> stream = ...
237 * final MinMax<SomeObject> moments = stream
238 * .collect(doubleMoments.toMinMax(comparator));
239 * }</pre>
240 *
241 * @param <C> the type of the input elements
242 * @return a {@code Collector} implementing the min-max reduction
243 * @throws java.lang.NullPointerException if the given {@code mapper} is
244 * {@code null}
245 */
246 public static <C extends Comparable<? super C>>
247 Collector<C, ?, MinMax<C>> toMinMax() {
248 return toMinMax(Comparator.naturalOrder());
249 }
250
251 /**
252 * Create a new {@code MinMax} <i>consumer</i> with the given
253 * {@link java.util.Comparator}.
254 *
255 * @param comparator the comparator used for comparing two elements
256 * @param <T> the element type
257 * @return a new {@code MinMax} <i>consumer</i>
258 * @throws java.lang.NullPointerException if the {@code comparator} is
259 * {@code null}.
260 */
261 public static <T> MinMax<T> of(final Comparator<? super T> comparator) {
262 return new MinMax<>(comparator);
263 }
264
265 /**
266 * Create a new {@code MinMax} <i>consumer</i>.
267 *
268 * @param <C> the element type
269 * @return a new {@code MinMax} <i>consumer</i>
270 */
271 public static <C extends Comparable<? super C>> MinMax<C> of() {
272 return of(Comparator.naturalOrder());
273 }
274
275 }
|