001 /*
002 * Java Genetic Algorithm Library (jenetics-3.9.0).
003 * Copyright (c) 2007-2017 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@gmx.at)
019 */
020 package org.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 * <p>
046 * <b>Implementation note:</b>
047 * <i>This implementation is not thread safe. However, it is safe to use on a
048 * parallel stream, because the parallel implementation of
049 * {@link java.util.stream.Stream#collect Stream.collect()}provides the
050 * necessary partitioning, isolation, and merging of results for safe and
051 * efficient parallel execution.</i>
052 *
053 * @author <a href="mailto:franz.wilhelmstoetter@gmx.at">Franz Wilhelmstötter</a>
054 * @since 3.0
055 * @version 3.7
056 */
057 public final class MinMax<C> implements Consumer<C> {
058
059 private final Comparator<? super C> _comparator;
060
061 private C _min;
062 private C _max;
063 private long _count = 0L;
064
065 private MinMax(final Comparator<? super C> comparator) {
066 _comparator = requireNonNull(comparator);
067 }
068
069 /**
070 * Accept the element for min-max calculation.
071 *
072 * @param object the element to use for min-max calculation
073 */
074 @Override
075 public void accept(final C object) {
076 _min = min(_comparator, _min, object);
077 _max = max(_comparator, _max, object);
078 ++_count;
079 }
080
081 /**
082 * Combine two {@code MinMax} objects.
083 *
084 * @param other the other {@code MinMax} object to combine
085 * @return {@code this}
086 * @throws java.lang.NullPointerException if the {@code other} object is
087 * {@code null}.
088 */
089 public MinMax<C> combine(final MinMax<C> other) {
090 _min = min(_comparator, _min, other._min);
091 _max = max(_comparator, _max, other._max);
092 _count += other._count;
093
094 return this;
095 }
096
097 /**
098 * Return the current minimal object or {@code null} if no element has been
099 * accepted yet.
100 *
101 * @return the current minimal object
102 */
103 public C getMin() {
104 return _min;
105 }
106
107 /**
108 * Return the current maximal object or {@code null} if no element has been
109 * accepted yet.
110 *
111 * @return the current maximal object
112 */
113 public C getMax() {
114 return _max;
115 }
116
117 /**
118 * Returns the count of values recorded.
119 *
120 * @return the count of recorded values
121 */
122 public long getCount() {
123 return _count;
124 }
125
126 /**
127 * Compares the state of two {@code LongMomentStatistics} objects. This is
128 * a replacement for the {@link #equals(Object)} which is not advisable to
129 * implement for this mutable object. If two object have the same state, it
130 * has still the same state when updated with the same value.
131 * <pre>{@code
132 * final MinMax mm1 = ...;
133 * final MinMax mm2 = ...;
134 *
135 * if (mm1.sameState(mm2)) {
136 * final long value = random.nextInt(1_000_000);
137 * mm1.accept(value);
138 * mm2.accept(value);
139 *
140 * assert mm1.sameState(mm2);
141 * assert mm2.sameState(mm1);
142 * assert mm1.sameState(mm1);
143 * }
144 * }</pre>
145 *
146 * @since 3.7
147 *
148 * @param other the other object for the test
149 * @return {@code true} the {@code this} and the {@code other} objects have
150 * the same state, {@code false} otherwise
151 */
152 public boolean sameState(final MinMax<C> other) {
153 return 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 }
|