|
1 | 1 | package com.javaquery.util.collection; |
2 | 2 |
|
| 3 | +import com.javaquery.util.Assert; |
3 | 4 | import com.javaquery.util.Objects; |
4 | 5 |
|
5 | 6 | import java.util.Collection; |
| 7 | +import java.util.HashMap; |
6 | 8 | import java.util.List; |
7 | 9 | import java.util.Map; |
8 | 10 | import java.util.stream.IntStream; |
@@ -91,4 +93,145 @@ public static <T> Stream<List<T>> batches(List<T> source, int batchSize) { |
91 | 93 | .range(0, fullChunks + 1) |
92 | 94 | .mapToObj(n -> source.subList(n * batchSize, n == fullChunks ? size : (n + 1) * batchSize)); |
93 | 95 | } |
| 96 | + |
| 97 | + /** |
| 98 | + * Note: Code imported from apache commons collection |
| 99 | + * <p> |
| 100 | + * Returns {@code true} iff the given {@link Collection}s contain |
| 101 | + * exactly the same elements with exactly the same cardinalities. |
| 102 | + * <p> |
| 103 | + * That is, iff the cardinality of <i>e</i> in <i>a</i> is |
| 104 | + * equal to the cardinality of <i>e</i> in <i>b</i>, |
| 105 | + * for each element <i>e</i> in <i>a</i> or <i>b</i>. |
| 106 | + * </p> |
| 107 | + * |
| 108 | + * @param collectionOne the first collection, must not be null |
| 109 | + * @param collectionTwo the second collection, must not be null |
| 110 | + * @return {@code true} iff the collections contain the same elements with the same cardinalities. |
| 111 | + * @throws NullPointerException if either collection is null |
| 112 | + * @since 1.0.3 |
| 113 | + */ |
| 114 | + public static <E> boolean isCollectionEqual(final Collection<E> collectionOne, final Collection<E> collectionTwo) { |
| 115 | + Assert.nonNull(collectionOne, NullPointerException::new); |
| 116 | + Assert.nonNull(collectionTwo, NullPointerException::new); |
| 117 | + |
| 118 | + if (collectionOne.size() != collectionTwo.size()) { |
| 119 | + return false; |
| 120 | + } |
| 121 | + |
| 122 | + final CardinalityHelper<Object> helper = new CardinalityHelper<>(collectionOne, collectionTwo); |
| 123 | + if (helper.cardinalityA.size() != helper.cardinalityB.size()) { |
| 124 | + return false; |
| 125 | + } |
| 126 | + for (final Object obj : helper.cardinalityA.keySet()) { |
| 127 | + if (helper.freqA(obj) != helper.freqB(obj)) { |
| 128 | + return false; |
| 129 | + } |
| 130 | + } |
| 131 | + return true; |
| 132 | + } |
| 133 | + |
| 134 | + /** |
| 135 | + * Note: Code imported from apache commons collection |
| 136 | + * Returns a {@link Map} mapping each unique element in the given |
| 137 | + * {@link Collection} to an {@link Integer} representing the number |
| 138 | + * of occurrences of that element in the {@link Collection}. |
| 139 | + * <p> |
| 140 | + * Only those elements present in the collection will appear as |
| 141 | + * keys in the map. |
| 142 | + * </p> |
| 143 | + * |
| 144 | + * @param <O> the type of object in the returned {@link Map}. This is a super type of <I>. |
| 145 | + * @param iterable the collection to get the cardinality map for, must not be null |
| 146 | + * @return the populated cardinality map |
| 147 | + * @throws NullPointerException if coll is null |
| 148 | + * @since 1.0.3 |
| 149 | + */ |
| 150 | + public static <O> Map<O, Integer> getCardinalityMap(final Iterable<? extends O> iterable) { |
| 151 | + Assert.nonNull(iterable, NullPointerException::new); |
| 152 | + final Map<O, Integer> count = new HashMap<>(); |
| 153 | + for (final O obj : iterable) { |
| 154 | + count.merge(obj, 1, Integer::sum); |
| 155 | + } |
| 156 | + return count; |
| 157 | + } |
| 158 | + |
| 159 | + /** |
| 160 | + * Note: Code imported from apache commons collection |
| 161 | + * Helper class to easily access cardinality properties of two collections. |
| 162 | + * |
| 163 | + * @param <O> the element type |
| 164 | + * @since 1.0.3 |
| 165 | + */ |
| 166 | + private static class CardinalityHelper<O> { |
| 167 | + |
| 168 | + /** |
| 169 | + * Contains the cardinality for each object in collection A. |
| 170 | + */ |
| 171 | + final Map<O, Integer> cardinalityA; |
| 172 | + |
| 173 | + /** |
| 174 | + * Contains the cardinality for each object in collection B. |
| 175 | + */ |
| 176 | + final Map<O, Integer> cardinalityB; |
| 177 | + |
| 178 | + /** |
| 179 | + * Create a new CardinalityHelper for two collections. |
| 180 | + * |
| 181 | + * @param a the first collection |
| 182 | + * @param b the second collection |
| 183 | + */ |
| 184 | + CardinalityHelper(final Iterable<? extends O> a, final Iterable<? extends O> b) { |
| 185 | + cardinalityA = Collections.getCardinalityMap(a); |
| 186 | + cardinalityB = Collections.getCardinalityMap(b); |
| 187 | + } |
| 188 | + |
| 189 | + /** |
| 190 | + * Returns the maximum frequency of an object. |
| 191 | + * |
| 192 | + * @param obj the object |
| 193 | + * @return the maximum frequency of the object |
| 194 | + */ |
| 195 | + public final int max(final Object obj) { |
| 196 | + return Math.max(freqA(obj), freqB(obj)); |
| 197 | + } |
| 198 | + |
| 199 | + /** |
| 200 | + * Returns the minimum frequency of an object. |
| 201 | + * |
| 202 | + * @param obj the object |
| 203 | + * @return the minimum frequency of the object |
| 204 | + */ |
| 205 | + public final int min(final Object obj) { |
| 206 | + return Math.min(freqA(obj), freqB(obj)); |
| 207 | + } |
| 208 | + |
| 209 | + /** |
| 210 | + * Returns the frequency of this object in collection A. |
| 211 | + * |
| 212 | + * @param obj the object |
| 213 | + * @return the frequency of the object in collection A |
| 214 | + */ |
| 215 | + public int freqA(final Object obj) { |
| 216 | + return getFreq(obj, cardinalityA); |
| 217 | + } |
| 218 | + |
| 219 | + /** |
| 220 | + * Returns the frequency of this object in collection B. |
| 221 | + * |
| 222 | + * @param obj the object |
| 223 | + * @return the frequency of the object in collection B |
| 224 | + */ |
| 225 | + public int freqB(final Object obj) { |
| 226 | + return getFreq(obj, cardinalityB); |
| 227 | + } |
| 228 | + |
| 229 | + private int getFreq(final Object obj, final Map<?, Integer> freqMap) { |
| 230 | + final Integer count = freqMap.get(obj); |
| 231 | + if (count != null) { |
| 232 | + return count; |
| 233 | + } |
| 234 | + return 0; |
| 235 | + } |
| 236 | + } |
94 | 237 | } |
0 commit comments