001 /*
002 * Java Genetic Algorithm Library (jenetics-4.3.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 this == other ||
153 Objects.equals(_min, other._min) &&
154 Objects.equals(_max, other._max);
155 }
156
157 @Override
158 public String toString() {
159 return format("MinMax[count=%d, min=%s, max=%s]", _count, _min, _max);
160 }
161
162 /* *************************************************************************
163 * Some static helper methods.
164 * ************************************************************************/
165
166 /**
167 * Return the minimum of two values, according the given comparator.
168 * {@code null} values are allowed.
169 *
170 * @param comp the comparator used for determining the min value
171 * @param a the first value to compare
172 * @param b the second value to compare
173 * @param <T> the type of the compared objects
174 * @return the minimum value, or {@code null} if both values are {@code null}.
175 * If only one value is {@code null}, the non {@code null} values is
176 * returned.
177 */
178 public static <T> T
179 min(final Comparator<? super T> comp, final T a, final T b) {
180 return a != null ? b != null ? comp.compare(a, b) <= 0 ? a : b : a : b;
181 }
182
183 /**
184 * Return the maximum of two values, according the given comparator.
185 * {@code null} values are allowed.
186 *
187 * @param comp the comparator used for determining the max value
188 * @param a the first value to compare
189 * @param b the second value to compare
190 * @param <T> the type of the compared objects
191 * @return the maximum value, or {@code null} if both values are {@code null}.
192 * If only one value is {@code null}, the non {@code null} values is
193 * returned.
194 */
195 public static <T> T
196 max(final Comparator<? super T> comp, final T a, final T b) {
197 return a != null ? b != null ? comp.compare(a, b) >= 0 ? a : b : a : b;
198 }
199
200
201 /* *************************************************************************
202 * Some static factory methods.
203 * ************************************************************************/
204
205 /**
206 * Return a {@code Collector} which calculates the minimum and maximum value.
207 * The given {@code comparator} is used for comparing two objects.
208 *
209 * <pre>{@code
210 * final Comparator<SomeObject> comparator = ...
211 * final Stream<SomeObject> stream = ...
212 * final MinMax<SomeObject> moments = stream
213 * .collect(doubleMoments.toMinMax(comparator));
214 * }</pre>
215 *
216 * @param comparator the {@code Comparator} to use
217 * @param <T> the type of the input elements
218 * @return a {@code Collector} implementing the min-max reduction
219 * @throws java.lang.NullPointerException if the given {@code mapper} is
220 * {@code null}
221 */
222 public static <T> Collector<T, ?, MinMax<T>>
223 toMinMax(final Comparator<? super T> comparator) {
224 requireNonNull(comparator);
225 return Collector.of(
226 () -> MinMax.of(comparator),
227 MinMax::accept,
228 MinMax::combine
229 );
230 }
231
232 /**
233 * Return a {@code Collector} which calculates the minimum and maximum value.
234 * The <i>reducing</i> objects must be comparable.
235 *
236 * <pre>{@code
237 * final Stream<SomeObject> stream = ...
238 * final MinMax<SomeObject> moments = stream
239 * .collect(doubleMoments.toMinMax(comparator));
240 * }</pre>
241 *
242 * @param <C> the type of the input elements
243 * @return a {@code Collector} implementing the min-max reduction
244 * @throws java.lang.NullPointerException if the given {@code mapper} is
245 * {@code null}
246 */
247 public static <C extends Comparable<? super C>>
248 Collector<C, ?, MinMax<C>> toMinMax() {
249 return toMinMax(Comparator.naturalOrder());
250 }
251
252 /**
253 * Create a new {@code MinMax} <i>consumer</i> with the given
254 * {@link java.util.Comparator}.
255 *
256 * @param comparator the comparator used for comparing two elements
257 * @param <T> the element type
258 * @return a new {@code MinMax} <i>consumer</i>
259 * @throws java.lang.NullPointerException if the {@code comparator} is
260 * {@code null}.
261 */
262 public static <T> MinMax<T> of(final Comparator<? super T> comparator) {
263 return new MinMax<>(comparator);
264 }
265
266 /**
267 * Create a new {@code MinMax} <i>consumer</i>.
268 *
269 * @param <C> the element type
270 * @return a new {@code MinMax} <i>consumer</i>
271 */
272 public static <C extends Comparable<? super C>> MinMax<C> of() {
273 return of(Comparator.naturalOrder());
274 }
275
276 }
|