001/* 002 * Copyright (C) 2007 The Guava Authors 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package com.google.common.collect; 018 019import static com.google.common.base.Preconditions.checkArgument; 020import static com.google.common.base.Preconditions.checkNotNull; 021import static com.google.common.base.Predicates.and; 022import static com.google.common.collect.CollectPreconditions.checkNonnegative; 023import static com.google.common.collect.CollectPreconditions.checkRemove; 024import static com.google.common.collect.Iterators.addAll; 025import static com.google.common.collect.Iterators.unmodifiableIterator; 026import static java.lang.Math.max; 027import static java.lang.Math.min; 028import static java.util.Arrays.asList; 029import static java.util.Arrays.sort; 030import static java.util.Collections.nCopies; 031import static java.util.Collections.unmodifiableSet; 032import static java.util.Objects.requireNonNull; 033 034import com.google.common.annotations.GwtCompatible; 035import com.google.common.annotations.GwtIncompatible; 036import com.google.common.annotations.J2ktIncompatible; 037import com.google.common.base.Predicate; 038import com.google.common.collect.Multiset.Entry; 039import com.google.common.math.IntMath; 040import com.google.common.primitives.Ints; 041import com.google.errorprone.annotations.CanIgnoreReturnValue; 042import com.google.errorprone.annotations.InlineMe; 043import com.google.errorprone.annotations.concurrent.LazyInit; 044import java.io.Serializable; 045import java.util.Collection; 046import java.util.Comparator; 047import java.util.Iterator; 048import java.util.NoSuchElementException; 049import java.util.Objects; 050import java.util.Set; 051import java.util.Spliterator; 052import java.util.function.Function; 053import java.util.function.Supplier; 054import java.util.function.ToIntFunction; 055import java.util.stream.Collector; 056import org.jspecify.annotations.Nullable; 057 058/** 059 * Provides static utility methods for creating and working with {@link Multiset} instances. 060 * 061 * <p>See the Guava User Guide article on <a href= 062 * "https://github.com/google/guava/wiki/CollectionUtilitiesExplained#multisets">{@code 063 * Multisets}</a>. 064 * 065 * @author Kevin Bourrillion 066 * @author Mike Bostock 067 * @author Louis Wasserman 068 * @since 2.0 069 */ 070@GwtCompatible 071public final class Multisets { 072 private Multisets() {} 073 074 /** 075 * Returns a {@code Collector} that accumulates elements into a multiset created via the specified 076 * {@code Supplier}, whose elements are the result of applying {@code elementFunction} to the 077 * inputs, with counts equal to the result of applying {@code countFunction} to the inputs. 078 * Elements are added in encounter order. 079 * 080 * <p>If the mapped elements contain duplicates (according to {@link Object#equals}), the element 081 * will be added more than once, with the count summed over all appearances of the element. 082 * 083 * <p>Note that {@code stream.collect(toMultiset(function, e -> 1, supplier))} is equivalent to 084 * {@code stream.map(function).collect(Collectors.toCollection(supplier))}. 085 * 086 * <p>To collect to an {@link ImmutableMultiset}, use {@link 087 * ImmutableMultiset#toImmutableMultiset}. 088 * 089 * @since 22.0 090 */ 091 public static <T extends @Nullable Object, E extends @Nullable Object, M extends Multiset<E>> 092 Collector<T, ?, M> toMultiset( 093 Function<? super T, E> elementFunction, 094 ToIntFunction<? super T> countFunction, 095 Supplier<M> multisetSupplier) { 096 return CollectCollectors.toMultiset(elementFunction, countFunction, multisetSupplier); 097 } 098 099 /** 100 * Returns an unmodifiable view of the specified multiset. Query operations on the returned 101 * multiset "read through" to the specified multiset, and attempts to modify the returned multiset 102 * result in an {@link UnsupportedOperationException}. 103 * 104 * <p>The returned multiset will be serializable if the specified multiset is serializable. 105 * 106 * @param multiset the multiset for which an unmodifiable view is to be generated 107 * @return an unmodifiable view of the multiset 108 */ 109 public static <E extends @Nullable Object> Multiset<E> unmodifiableMultiset( 110 Multiset<? extends E> multiset) { 111 if (multiset instanceof UnmodifiableMultiset || multiset instanceof ImmutableMultiset) { 112 @SuppressWarnings("unchecked") // Since it's unmodifiable, the covariant cast is safe 113 Multiset<E> result = (Multiset<E>) multiset; 114 return result; 115 } 116 return new UnmodifiableMultiset<>(checkNotNull(multiset)); 117 } 118 119 /** 120 * Simply returns its argument. 121 * 122 * @deprecated no need to use this 123 * @since 10.0 124 */ 125 @InlineMe( 126 replacement = "checkNotNull(multiset)", 127 staticImports = "com.google.common.base.Preconditions.checkNotNull") 128 @Deprecated 129 public static <E> Multiset<E> unmodifiableMultiset(ImmutableMultiset<E> multiset) { 130 return checkNotNull(multiset); 131 } 132 133 static class UnmodifiableMultiset<E extends @Nullable Object> extends ForwardingMultiset<E> 134 implements Serializable { 135 final Multiset<? extends E> delegate; 136 137 UnmodifiableMultiset(Multiset<? extends E> delegate) { 138 this.delegate = delegate; 139 } 140 141 @SuppressWarnings("unchecked") 142 @Override 143 protected Multiset<E> delegate() { 144 // This is safe because all non-covariant methods are overridden 145 return (Multiset<E>) delegate; 146 } 147 148 @LazyInit transient @Nullable Set<E> elementSet; 149 150 Set<E> createElementSet() { 151 return unmodifiableSet(delegate.elementSet()); 152 } 153 154 @Override 155 public Set<E> elementSet() { 156 Set<E> result = elementSet; 157 if (result == null) { 158 result = elementSet = createElementSet(); 159 } 160 return result; 161 } 162 163 @LazyInit transient @Nullable Set<Entry<E>> entrySet; 164 165 @SuppressWarnings("unchecked") 166 @Override 167 public Set<Entry<E>> entrySet() { 168 Set<Entry<E>> result = entrySet; 169 if (result == null) { 170 // Safe because the returned set is made unmodifiable and Entry 171 // itself is readonly 172 result = entrySet = (Set) unmodifiableSet(delegate.entrySet()); 173 } 174 return result; 175 } 176 177 @Override 178 public Iterator<E> iterator() { 179 return unmodifiableIterator(delegate.iterator()); 180 } 181 182 @Override 183 public boolean add(@ParametricNullness E element) { 184 throw new UnsupportedOperationException(); 185 } 186 187 @Override 188 public int add(@ParametricNullness E element, int occurrences) { 189 throw new UnsupportedOperationException(); 190 } 191 192 @Override 193 public boolean addAll(Collection<? extends E> elementsToAdd) { 194 throw new UnsupportedOperationException(); 195 } 196 197 @Override 198 public boolean remove(@Nullable Object element) { 199 throw new UnsupportedOperationException(); 200 } 201 202 @Override 203 public int remove(@Nullable Object element, int occurrences) { 204 throw new UnsupportedOperationException(); 205 } 206 207 @Override 208 public boolean removeAll(Collection<?> elementsToRemove) { 209 throw new UnsupportedOperationException(); 210 } 211 212 @Override 213 public boolean removeIf(java.util.function.Predicate<? super E> filter) { 214 throw new UnsupportedOperationException(); 215 } 216 217 @Override 218 public boolean retainAll(Collection<?> elementsToRetain) { 219 throw new UnsupportedOperationException(); 220 } 221 222 @Override 223 public void clear() { 224 throw new UnsupportedOperationException(); 225 } 226 227 @Override 228 public int setCount(@ParametricNullness E element, int count) { 229 throw new UnsupportedOperationException(); 230 } 231 232 @Override 233 public boolean setCount(@ParametricNullness E element, int oldCount, int newCount) { 234 throw new UnsupportedOperationException(); 235 } 236 237 @GwtIncompatible @J2ktIncompatible private static final long serialVersionUID = 0; 238 } 239 240 /** 241 * Returns an unmodifiable view of the specified sorted multiset. Query operations on the returned 242 * multiset "read through" to the specified multiset, and attempts to modify the returned multiset 243 * result in an {@link UnsupportedOperationException}. 244 * 245 * <p>The returned multiset will be serializable if the specified multiset is serializable. 246 * 247 * @param sortedMultiset the sorted multiset for which an unmodifiable view is to be generated 248 * @return an unmodifiable view of the multiset 249 * @since 11.0 250 */ 251 public static <E extends @Nullable Object> SortedMultiset<E> unmodifiableSortedMultiset( 252 SortedMultiset<E> sortedMultiset) { 253 // it's in its own file so it can be emulated for GWT 254 return new UnmodifiableSortedMultiset<>(checkNotNull(sortedMultiset)); 255 } 256 257 /** 258 * Returns an immutable multiset entry with the specified element and count. The entry will be 259 * serializable if {@code e} is. 260 * 261 * @param e the element to be associated with the returned entry 262 * @param n the count to be associated with the returned entry 263 * @throws IllegalArgumentException if {@code n} is negative 264 */ 265 public static <E extends @Nullable Object> Multiset.Entry<E> immutableEntry( 266 @ParametricNullness E e, int n) { 267 return new ImmutableEntry<>(e, n); 268 } 269 270 static class ImmutableEntry<E extends @Nullable Object> extends AbstractEntry<E> 271 implements Serializable { 272 @ParametricNullness private final E element; 273 private final int count; 274 275 ImmutableEntry(@ParametricNullness E element, int count) { 276 this.element = element; 277 this.count = count; 278 checkNonnegative(count, "count"); 279 } 280 281 @Override 282 @ParametricNullness 283 public final E getElement() { 284 return element; 285 } 286 287 @Override 288 public final int getCount() { 289 return count; 290 } 291 292 public @Nullable ImmutableEntry<E> nextInBucket() { 293 return null; 294 } 295 296 @GwtIncompatible @J2ktIncompatible private static final long serialVersionUID = 0; 297 } 298 299 /** 300 * Returns a view of the elements of {@code unfiltered} that satisfy a predicate. The returned 301 * multiset is a live view of {@code unfiltered}; changes to one affect the other. 302 * 303 * <p>The resulting multiset's iterators, and those of its {@code entrySet()} and {@code 304 * elementSet()}, do not support {@code remove()}. However, all other multiset methods supported 305 * by {@code unfiltered} are supported by the returned multiset. When given an element that 306 * doesn't satisfy the predicate, the multiset's {@code add()} and {@code addAll()} methods throw 307 * an {@link IllegalArgumentException}. When methods such as {@code removeAll()} and {@code 308 * clear()} are called on the filtered multiset, only elements that satisfy the filter will be 309 * removed from the underlying multiset. 310 * 311 * <p>The returned multiset isn't threadsafe or serializable, even if {@code unfiltered} is. 312 * 313 * <p>Many of the filtered multiset's methods, such as {@code size()}, iterate across every 314 * element in the underlying multiset and determine which elements satisfy the filter. When a live 315 * view is <i>not</i> needed, it may be faster to copy the returned multiset and use the copy. 316 * 317 * <p><b>Warning:</b> {@code predicate} must be <i>consistent with equals</i>, as documented at 318 * {@link Predicate#apply}. Do not provide a predicate such as {@code 319 * Predicates.instanceOf(ArrayList.class)}, which is inconsistent with equals. (See {@link 320 * Iterables#filter(Iterable, Class)} for related functionality.) 321 * 322 * @since 14.0 323 */ 324 public static <E extends @Nullable Object> Multiset<E> filter( 325 Multiset<E> unfiltered, Predicate<? super E> predicate) { 326 if (unfiltered instanceof FilteredMultiset) { 327 // Support clear(), removeAll(), and retainAll() when filtering a filtered 328 // collection. 329 FilteredMultiset<E> filtered = (FilteredMultiset<E>) unfiltered; 330 Predicate<E> combinedPredicate = and(filtered.predicate, predicate); 331 return new FilteredMultiset<>(filtered.unfiltered, combinedPredicate); 332 } 333 return new FilteredMultiset<>(unfiltered, predicate); 334 } 335 336 private static final class FilteredMultiset<E extends @Nullable Object> extends ViewMultiset<E> { 337 final Multiset<E> unfiltered; 338 final Predicate<? super E> predicate; 339 340 FilteredMultiset(Multiset<E> unfiltered, Predicate<? super E> predicate) { 341 this.unfiltered = checkNotNull(unfiltered); 342 this.predicate = checkNotNull(predicate); 343 } 344 345 @Override 346 public UnmodifiableIterator<E> iterator() { 347 return Iterators.filter(unfiltered.iterator(), predicate); 348 } 349 350 @Override 351 Set<E> createElementSet() { 352 return Sets.filter(unfiltered.elementSet(), predicate); 353 } 354 355 @Override 356 Iterator<E> elementIterator() { 357 throw new AssertionError("should never be called"); 358 } 359 360 @Override 361 Set<Entry<E>> createEntrySet() { 362 return Sets.filter(unfiltered.entrySet(), entry -> predicate.apply(entry.getElement())); 363 } 364 365 @Override 366 Iterator<Entry<E>> entryIterator() { 367 throw new AssertionError("should never be called"); 368 } 369 370 @Override 371 public int count(@Nullable Object element) { 372 int count = unfiltered.count(element); 373 if (count > 0) { 374 @SuppressWarnings("unchecked") // element is equal to an E 375 E e = (E) element; 376 return predicate.apply(e) ? count : 0; 377 } 378 return 0; 379 } 380 381 @Override 382 public int add(@ParametricNullness E element, int occurrences) { 383 checkArgument( 384 predicate.apply(element), "Element %s does not match predicate %s", element, predicate); 385 return unfiltered.add(element, occurrences); 386 } 387 388 @Override 389 public int remove(@Nullable Object element, int occurrences) { 390 checkNonnegative(occurrences, "occurrences"); 391 if (occurrences == 0) { 392 return count(element); 393 } else { 394 return contains(element) ? unfiltered.remove(element, occurrences) : 0; 395 } 396 } 397 } 398 399 /** 400 * Returns the expected number of distinct elements given the specified elements. The number of 401 * distinct elements is only computed if {@code elements} is an instance of {@code Multiset}; 402 * otherwise the default value of 11 is returned. 403 */ 404 static int inferDistinctElements(Iterable<?> elements) { 405 if (elements instanceof Multiset) { 406 return ((Multiset<?>) elements).elementSet().size(); 407 } 408 return 11; // initial capacity will be rounded up to 16 409 } 410 411 /** 412 * Returns an unmodifiable view of the union of two multisets. In the returned multiset, the count 413 * of each element is the <i>maximum</i> of its counts in the two backing multisets. The iteration 414 * order of the returned multiset matches that of the element set of {@code multiset1} followed by 415 * the members of the element set of {@code multiset2} that are not contained in {@code 416 * multiset1}, with repeated occurrences of the same element appearing consecutively. 417 * 418 * <p>Results are undefined if {@code multiset1} and {@code multiset2} are based on different 419 * equivalence relations (as {@code HashMultiset} and {@code TreeMultiset} are). 420 * 421 * @since 14.0 422 */ 423 public static <E extends @Nullable Object> Multiset<E> union( 424 Multiset<? extends E> multiset1, Multiset<? extends E> multiset2) { 425 checkNotNull(multiset1); 426 checkNotNull(multiset2); 427 428 return new ViewMultiset<E>() { 429 @Override 430 public boolean contains(@Nullable Object element) { 431 return multiset1.contains(element) || multiset2.contains(element); 432 } 433 434 @Override 435 public boolean isEmpty() { 436 return multiset1.isEmpty() && multiset2.isEmpty(); 437 } 438 439 @Override 440 public int count(@Nullable Object element) { 441 return max(multiset1.count(element), multiset2.count(element)); 442 } 443 444 @Override 445 Set<E> createElementSet() { 446 return Sets.union(multiset1.elementSet(), multiset2.elementSet()); 447 } 448 449 @Override 450 Iterator<E> elementIterator() { 451 throw new AssertionError("should never be called"); 452 } 453 454 @Override 455 Iterator<Entry<E>> entryIterator() { 456 Iterator<? extends Entry<? extends E>> iterator1 = multiset1.entrySet().iterator(); 457 Iterator<? extends Entry<? extends E>> iterator2 = multiset2.entrySet().iterator(); 458 // TODO(lowasser): consider making the entries live views 459 return new AbstractIterator<Entry<E>>() { 460 @Override 461 protected @Nullable Entry<E> computeNext() { 462 if (iterator1.hasNext()) { 463 Entry<? extends E> entry1 = iterator1.next(); 464 E element = entry1.getElement(); 465 int count = max(entry1.getCount(), multiset2.count(element)); 466 return immutableEntry(element, count); 467 } 468 while (iterator2.hasNext()) { 469 Entry<? extends E> entry2 = iterator2.next(); 470 E element = entry2.getElement(); 471 if (!multiset1.contains(element)) { 472 return immutableEntry(element, entry2.getCount()); 473 } 474 } 475 return endOfData(); 476 } 477 }; 478 } 479 }; 480 } 481 482 /** 483 * Returns an unmodifiable view of the intersection of two multisets. In the returned multiset, 484 * the count of each element is the <i>minimum</i> of its counts in the two backing multisets, 485 * with elements that would have a count of 0 not included. The iteration order of the returned 486 * multiset matches that of the element set of {@code multiset1}, with repeated occurrences of the 487 * same element appearing consecutively. 488 * 489 * <p>Results are undefined if {@code multiset1} and {@code multiset2} are based on different 490 * equivalence relations (as {@code HashMultiset} and {@code TreeMultiset} are). 491 * 492 * @since 2.0 493 */ 494 public static <E extends @Nullable Object> Multiset<E> intersection( 495 Multiset<E> multiset1, Multiset<?> multiset2) { 496 checkNotNull(multiset1); 497 checkNotNull(multiset2); 498 499 return new ViewMultiset<E>() { 500 @Override 501 public int count(@Nullable Object element) { 502 int count1 = multiset1.count(element); 503 return (count1 == 0) ? 0 : min(count1, multiset2.count(element)); 504 } 505 506 @Override 507 Set<E> createElementSet() { 508 return Sets.intersection(multiset1.elementSet(), multiset2.elementSet()); 509 } 510 511 @Override 512 Iterator<E> elementIterator() { 513 throw new AssertionError("should never be called"); 514 } 515 516 @Override 517 Iterator<Entry<E>> entryIterator() { 518 Iterator<Entry<E>> iterator1 = multiset1.entrySet().iterator(); 519 // TODO(lowasser): consider making the entries live views 520 return new AbstractIterator<Entry<E>>() { 521 @Override 522 protected @Nullable Entry<E> computeNext() { 523 while (iterator1.hasNext()) { 524 Entry<E> entry1 = iterator1.next(); 525 E element = entry1.getElement(); 526 int count = min(entry1.getCount(), multiset2.count(element)); 527 if (count > 0) { 528 return immutableEntry(element, count); 529 } 530 } 531 return endOfData(); 532 } 533 }; 534 } 535 }; 536 } 537 538 /** 539 * Returns an unmodifiable view of the sum of two multisets. In the returned multiset, the count 540 * of each element is the <i>sum</i> of its counts in the two backing multisets. Sums are capped 541 * at {@link Integer#MAX_VALUE}. 542 * 543 * <p>The iteration order of the returned multiset matches that of the element set of {@code 544 * multiset1} followed by the members of the element set of {@code multiset2} that are not 545 * contained in {@code multiset1}, with repeated occurrences of the same element appearing 546 * consecutively. 547 * 548 * <p>Results are undefined if {@code multiset1} and {@code multiset2} are based on different 549 * equivalence relations (as {@code HashMultiset} and {@code TreeMultiset} are). 550 * 551 * @since 14.0 552 */ 553 public static <E extends @Nullable Object> Multiset<E> sum( 554 Multiset<? extends E> multiset1, Multiset<? extends E> multiset2) { 555 checkNotNull(multiset1); 556 checkNotNull(multiset2); 557 558 // TODO(lowasser): consider making the entries live views 559 return new ViewMultiset<E>() { 560 @Override 561 public boolean contains(@Nullable Object element) { 562 return multiset1.contains(element) || multiset2.contains(element); 563 } 564 565 @Override 566 public boolean isEmpty() { 567 return multiset1.isEmpty() && multiset2.isEmpty(); 568 } 569 570 @Override 571 public int size() { 572 return IntMath.saturatedAdd(multiset1.size(), multiset2.size()); 573 } 574 575 @Override 576 public int count(@Nullable Object element) { 577 return IntMath.saturatedAdd(multiset1.count(element), multiset2.count(element)); 578 } 579 580 @Override 581 Set<E> createElementSet() { 582 return Sets.union(multiset1.elementSet(), multiset2.elementSet()); 583 } 584 585 @Override 586 Iterator<E> elementIterator() { 587 throw new AssertionError("should never be called"); 588 } 589 590 @Override 591 Iterator<Entry<E>> entryIterator() { 592 Iterator<? extends Entry<? extends E>> iterator1 = multiset1.entrySet().iterator(); 593 Iterator<? extends Entry<? extends E>> iterator2 = multiset2.entrySet().iterator(); 594 return new AbstractIterator<Entry<E>>() { 595 @Override 596 protected @Nullable Entry<E> computeNext() { 597 if (iterator1.hasNext()) { 598 Entry<? extends E> entry1 = iterator1.next(); 599 E element = entry1.getElement(); 600 int count = IntMath.saturatedAdd(entry1.getCount(), multiset2.count(element)); 601 return immutableEntry(element, count); 602 } 603 while (iterator2.hasNext()) { 604 Entry<? extends E> entry2 = iterator2.next(); 605 E element = entry2.getElement(); 606 if (!multiset1.contains(element)) { 607 return immutableEntry(element, entry2.getCount()); 608 } 609 } 610 return endOfData(); 611 } 612 }; 613 } 614 }; 615 } 616 617 /** 618 * Returns an unmodifiable view of the difference of two multisets. In the returned multiset, the 619 * count of each element is the result of the <i>zero-truncated subtraction</i> of its count in 620 * the second multiset from its count in the first multiset, with elements that would have a count 621 * of 0 not included. The iteration order of the returned multiset matches that of the element set 622 * of {@code multiset1}, with repeated occurrences of the same element appearing consecutively. 623 * 624 * <p>Results are undefined if {@code multiset1} and {@code multiset2} are based on different 625 * equivalence relations (as {@code HashMultiset} and {@code TreeMultiset} are). 626 * 627 * @since 14.0 628 */ 629 public static <E extends @Nullable Object> Multiset<E> difference( 630 Multiset<E> multiset1, Multiset<?> multiset2) { 631 checkNotNull(multiset1); 632 checkNotNull(multiset2); 633 634 // TODO(lowasser): consider making the entries live views 635 return new ViewMultiset<E>() { 636 @Override 637 public int count(@Nullable Object element) { 638 int count1 = multiset1.count(element); 639 return (count1 == 0) ? 0 : max(0, count1 - multiset2.count(element)); 640 } 641 642 @Override 643 public void clear() { 644 throw new UnsupportedOperationException(); 645 } 646 647 @Override 648 Iterator<E> elementIterator() { 649 Iterator<Entry<E>> iterator1 = multiset1.entrySet().iterator(); 650 return new AbstractIterator<E>() { 651 @Override 652 protected @Nullable E computeNext() { 653 while (iterator1.hasNext()) { 654 Entry<E> entry1 = iterator1.next(); 655 E element = entry1.getElement(); 656 if (entry1.getCount() > multiset2.count(element)) { 657 return element; 658 } 659 } 660 return endOfData(); 661 } 662 }; 663 } 664 665 @Override 666 Iterator<Entry<E>> entryIterator() { 667 Iterator<Entry<E>> iterator1 = multiset1.entrySet().iterator(); 668 return new AbstractIterator<Entry<E>>() { 669 @Override 670 protected @Nullable Entry<E> computeNext() { 671 while (iterator1.hasNext()) { 672 Entry<E> entry1 = iterator1.next(); 673 E element = entry1.getElement(); 674 int count = entry1.getCount() - multiset2.count(element); 675 if (count > 0) { 676 return immutableEntry(element, count); 677 } 678 } 679 return endOfData(); 680 } 681 }; 682 } 683 684 @Override 685 int distinctElements() { 686 return Iterators.size(entryIterator()); 687 } 688 }; 689 } 690 691 /** 692 * Returns {@code true} if {@code subMultiset.count(o) <= superMultiset.count(o)} for all {@code 693 * o}. 694 * 695 * @since 10.0 696 */ 697 @CanIgnoreReturnValue 698 public static boolean containsOccurrences(Multiset<?> superMultiset, Multiset<?> subMultiset) { 699 checkNotNull(superMultiset); 700 checkNotNull(subMultiset); 701 for (Entry<?> entry : subMultiset.entrySet()) { 702 int superCount = superMultiset.count(entry.getElement()); 703 if (superCount < entry.getCount()) { 704 return false; 705 } 706 } 707 return true; 708 } 709 710 /** 711 * Modifies {@code multisetToModify} so that its count for an element {@code e} is at most {@code 712 * multisetToRetain.count(e)}. 713 * 714 * <p>To be precise, {@code multisetToModify.count(e)} is set to {@code 715 * Math.min(multisetToModify.count(e), multisetToRetain.count(e))}. This is similar to {@link 716 * #intersection(Multiset, Multiset) intersection} {@code (multisetToModify, multisetToRetain)}, 717 * but mutates {@code multisetToModify} instead of returning a view. 718 * 719 * <p>In contrast, {@code multisetToModify.retainAll(multisetToRetain)} keeps all occurrences of 720 * elements that appear at all in {@code multisetToRetain}, and deletes all occurrences of all 721 * other elements. 722 * 723 * @return {@code true} if {@code multisetToModify} was changed as a result of this operation 724 * @since 10.0 725 */ 726 @CanIgnoreReturnValue 727 public static boolean retainOccurrences( 728 Multiset<?> multisetToModify, Multiset<?> multisetToRetain) { 729 return retainOccurrencesImpl(multisetToModify, multisetToRetain); 730 } 731 732 /** Delegate implementation which cares about the element type. */ 733 private static <E extends @Nullable Object> boolean retainOccurrencesImpl( 734 Multiset<E> multisetToModify, Multiset<?> occurrencesToRetain) { 735 checkNotNull(multisetToModify); 736 checkNotNull(occurrencesToRetain); 737 // Avoiding ConcurrentModificationExceptions is tricky. 738 Iterator<Entry<E>> entryIterator = multisetToModify.entrySet().iterator(); 739 boolean changed = false; 740 while (entryIterator.hasNext()) { 741 Entry<E> entry = entryIterator.next(); 742 int retainCount = occurrencesToRetain.count(entry.getElement()); 743 if (retainCount == 0) { 744 entryIterator.remove(); 745 changed = true; 746 } else if (retainCount < entry.getCount()) { 747 multisetToModify.setCount(entry.getElement(), retainCount); 748 changed = true; 749 } 750 } 751 return changed; 752 } 753 754 /** 755 * For each occurrence of an element {@code e} in {@code occurrencesToRemove}, removes one 756 * occurrence of {@code e} in {@code multisetToModify}. 757 * 758 * <p>Equivalently, this method modifies {@code multisetToModify} so that {@code 759 * multisetToModify.count(e)} is set to {@code Math.max(0, multisetToModify.count(e) - 760 * Iterables.frequency(occurrencesToRemove, e))}. 761 * 762 * <p>This is <i>not</i> the same as {@code multisetToModify.} {@link Multiset#removeAll 763 * removeAll}{@code (occurrencesToRemove)}, which removes all occurrences of elements that appear 764 * in {@code occurrencesToRemove}. However, this operation <i>is</i> equivalent to, albeit 765 * sometimes more efficient than, the following: 766 * 767 * {@snippet : 768 * for (E e : occurrencesToRemove) { 769 * multisetToModify.remove(e); 770 * } 771 * } 772 * 773 * @return {@code true} if {@code multisetToModify} was changed as a result of this operation 774 * @since 18.0 (present in 10.0 with a requirement that the second parameter be a {@code 775 * Multiset}) 776 */ 777 @CanIgnoreReturnValue 778 public static boolean removeOccurrences( 779 Multiset<?> multisetToModify, Iterable<?> occurrencesToRemove) { 780 if (occurrencesToRemove instanceof Multiset) { 781 return removeOccurrences(multisetToModify, (Multiset<?>) occurrencesToRemove); 782 } else { 783 checkNotNull(multisetToModify); 784 checkNotNull(occurrencesToRemove); 785 boolean changed = false; 786 for (Object o : occurrencesToRemove) { 787 changed |= multisetToModify.remove(o); 788 } 789 return changed; 790 } 791 } 792 793 /** 794 * For each occurrence of an element {@code e} in {@code occurrencesToRemove}, removes one 795 * occurrence of {@code e} in {@code multisetToModify}. 796 * 797 * <p>Equivalently, this method modifies {@code multisetToModify} so that {@code 798 * multisetToModify.count(e)} is set to {@code Math.max(0, multisetToModify.count(e) - 799 * occurrencesToRemove.count(e))}. 800 * 801 * <p>This is <i>not</i> the same as {@code multisetToModify.} {@link Multiset#removeAll 802 * removeAll}{@code (occurrencesToRemove)}, which removes all occurrences of elements that appear 803 * in {@code occurrencesToRemove}. However, this operation <i>is</i> equivalent to, albeit 804 * sometimes more efficient than, the following: 805 * 806 * {@snippet : 807 * for (E e : occurrencesToRemove) { 808 * multisetToModify.remove(e); 809 * } 810 * } 811 * 812 * @return {@code true} if {@code multisetToModify} was changed as a result of this operation 813 * @since 10.0 (missing in 18.0 when only the overload taking an {@code Iterable} was present) 814 */ 815 @CanIgnoreReturnValue 816 public static boolean removeOccurrences( 817 Multiset<?> multisetToModify, Multiset<?> occurrencesToRemove) { 818 checkNotNull(multisetToModify); 819 checkNotNull(occurrencesToRemove); 820 821 boolean changed = false; 822 Iterator<? extends Entry<?>> entryIterator = multisetToModify.entrySet().iterator(); 823 while (entryIterator.hasNext()) { 824 Entry<?> entry = entryIterator.next(); 825 int removeCount = occurrencesToRemove.count(entry.getElement()); 826 if (removeCount >= entry.getCount()) { 827 entryIterator.remove(); 828 changed = true; 829 } else if (removeCount > 0) { 830 multisetToModify.remove(entry.getElement(), removeCount); 831 changed = true; 832 } 833 } 834 return changed; 835 } 836 837 /** 838 * Implementation of the {@code equals}, {@code hashCode}, and {@code toString} methods of {@link 839 * Multiset.Entry}. 840 */ 841 abstract static class AbstractEntry<E extends @Nullable Object> implements Multiset.Entry<E> { 842 /** 843 * Indicates whether an object equals this entry, following the behavior specified in {@link 844 * Multiset.Entry#equals}. 845 */ 846 @Override 847 public boolean equals(@Nullable Object object) { 848 if (object instanceof Multiset.Entry) { 849 Multiset.Entry<?> that = (Multiset.Entry<?>) object; 850 return this.getCount() == that.getCount() 851 && Objects.equals(this.getElement(), that.getElement()); 852 } 853 return false; 854 } 855 856 /** 857 * Return this entry's hash code, following the behavior specified in {@link 858 * Multiset.Entry#hashCode}. 859 */ 860 @Override 861 public int hashCode() { 862 E e = getElement(); 863 return ((e == null) ? 0 : e.hashCode()) ^ getCount(); 864 } 865 866 /** 867 * Returns a string representation of this multiset entry. The string representation consists of 868 * the associated element if the associated count is one, and otherwise the associated element 869 * followed by the characters " x " (space, x and space) followed by the count. Elements and 870 * counts are converted to strings as by {@code String.valueOf}. 871 */ 872 @Override 873 public String toString() { 874 String text = String.valueOf(getElement()); 875 int n = getCount(); 876 return (n == 1) ? text : (text + " x " + n); 877 } 878 } 879 880 /** An implementation of {@link Multiset#equals}. */ 881 @SuppressWarnings("ReferenceEquality") // == fast path 882 static boolean equalsImpl(Multiset<?> multiset, @Nullable Object object) { 883 if (object == multiset) { 884 return true; 885 } 886 if (object instanceof Multiset) { 887 Multiset<?> that = (Multiset<?>) object; 888 /* 889 * We can't simply check whether the entry sets are equal, since that 890 * approach fails when a TreeMultiset has a comparator that returns 0 891 * when passed unequal elements. 892 */ 893 894 if (multiset.size() != that.size() || multiset.entrySet().size() != that.entrySet().size()) { 895 return false; 896 } 897 for (Entry<?> entry : that.entrySet()) { 898 if (multiset.count(entry.getElement()) != entry.getCount()) { 899 return false; 900 } 901 } 902 return true; 903 } 904 return false; 905 } 906 907 /** An implementation of {@link Multiset#addAll}. */ 908 static <E extends @Nullable Object> boolean addAllImpl( 909 Multiset<E> self, Collection<? extends E> elements) { 910 checkNotNull(self); 911 checkNotNull(elements); 912 if (elements instanceof Multiset) { 913 return addAllImpl(self, (Multiset<? extends E>) elements); 914 } else if (elements.isEmpty()) { 915 return false; 916 } else { 917 return addAll(self, elements.iterator()); 918 } 919 } 920 921 /** A specialization of {@code addAllImpl} for when {@code elements} is itself a Multiset. */ 922 private static <E extends @Nullable Object> boolean addAllImpl( 923 Multiset<E> self, Multiset<? extends E> elements) { 924 if (elements.isEmpty()) { 925 return false; 926 } 927 elements.forEachEntry(self::add); 928 return true; 929 } 930 931 /** An implementation of {@link Multiset#removeAll}. */ 932 static boolean removeAllImpl(Multiset<?> self, Collection<?> elementsToRemove) { 933 Collection<?> collection = 934 (elementsToRemove instanceof Multiset) 935 ? ((Multiset<?>) elementsToRemove).elementSet() 936 : elementsToRemove; 937 938 return self.elementSet().removeAll(collection); 939 } 940 941 /** An implementation of {@link Multiset#retainAll}. */ 942 static boolean retainAllImpl(Multiset<?> self, Collection<?> elementsToRetain) { 943 checkNotNull(elementsToRetain); 944 Collection<?> collection = 945 (elementsToRetain instanceof Multiset) 946 ? ((Multiset<?>) elementsToRetain).elementSet() 947 : elementsToRetain; 948 949 return self.elementSet().retainAll(collection); 950 } 951 952 /** An implementation of {@link Multiset#setCount(Object, int)}. */ 953 static <E extends @Nullable Object> int setCountImpl( 954 Multiset<E> self, @ParametricNullness E element, int count) { 955 checkNonnegative(count, "count"); 956 957 int oldCount = self.count(element); 958 959 int delta = count - oldCount; 960 if (delta > 0) { 961 self.add(element, delta); 962 } else if (delta < 0) { 963 self.remove(element, -delta); 964 } 965 966 return oldCount; 967 } 968 969 /** An implementation of {@link Multiset#setCount(Object, int, int)}. */ 970 static <E extends @Nullable Object> boolean setCountImpl( 971 Multiset<E> self, @ParametricNullness E element, int oldCount, int newCount) { 972 checkNonnegative(oldCount, "oldCount"); 973 checkNonnegative(newCount, "newCount"); 974 975 if (self.count(element) == oldCount) { 976 self.setCount(element, newCount); 977 return true; 978 } else { 979 return false; 980 } 981 } 982 983 static <E extends @Nullable Object> Iterator<E> elementIterator( 984 Iterator<Entry<E>> entryIterator) { 985 return new TransformedIterator<Entry<E>, E>(entryIterator) { 986 @Override 987 @ParametricNullness 988 E transform(Entry<E> entry) { 989 return entry.getElement(); 990 } 991 }; 992 } 993 994 abstract static class ElementSet<E extends @Nullable Object> extends Sets.ImprovedAbstractSet<E> { 995 abstract Multiset<E> multiset(); 996 997 @Override 998 public void clear() { 999 multiset().clear(); 1000 } 1001 1002 @Override 1003 public boolean contains(@Nullable Object o) { 1004 return multiset().contains(o); 1005 } 1006 1007 @Override 1008 public boolean containsAll(Collection<?> c) { 1009 return multiset().containsAll(c); 1010 } 1011 1012 @Override 1013 public boolean isEmpty() { 1014 return multiset().isEmpty(); 1015 } 1016 1017 @Override 1018 public abstract Iterator<E> iterator(); 1019 1020 @Override 1021 public boolean remove(@Nullable Object o) { 1022 return multiset().remove(o, Integer.MAX_VALUE) > 0; 1023 } 1024 1025 @Override 1026 public int size() { 1027 return multiset().entrySet().size(); 1028 } 1029 } 1030 1031 abstract static class EntrySet<E extends @Nullable Object> 1032 extends Sets.ImprovedAbstractSet<Entry<E>> { 1033 abstract Multiset<E> multiset(); 1034 1035 @Override 1036 public final boolean contains(@Nullable Object o) { 1037 if (o instanceof Entry) { 1038 Entry<?> entry = (Entry<?>) o; 1039 if (entry.getCount() <= 0) { 1040 return false; 1041 } 1042 int count = multiset().count(entry.getElement()); 1043 return count == entry.getCount(); 1044 } 1045 return false; 1046 } 1047 1048 @Override 1049 public boolean remove(@Nullable Object object) { 1050 if (object instanceof Multiset.Entry) { 1051 Entry<?> entry = (Entry<?>) object; 1052 Object element = entry.getElement(); 1053 int entryCount = entry.getCount(); 1054 if (entryCount != 0) { 1055 // Safe as long as we never add a new entry, which we won't. 1056 // (Presumably it can still throw CCE/NPE but only if the underlying Multiset does.) 1057 @SuppressWarnings({"unchecked", "nullness"}) 1058 Multiset<@Nullable Object> multiset = (Multiset<@Nullable Object>) multiset(); 1059 return multiset.setCount(element, entryCount, 0); 1060 } 1061 } 1062 return false; 1063 } 1064 1065 @Override 1066 public final void clear() { 1067 multiset().clear(); 1068 } 1069 } 1070 1071 /** An implementation of {@link Multiset#iterator}. */ 1072 static <E extends @Nullable Object> Iterator<E> iteratorImpl(Multiset<E> multiset) { 1073 return new MultisetIteratorImpl<>(multiset, multiset.entrySet().iterator()); 1074 } 1075 1076 static final class MultisetIteratorImpl<E extends @Nullable Object> implements Iterator<E> { 1077 private final Multiset<E> multiset; 1078 private final Iterator<Entry<E>> entryIterator; 1079 private @Nullable Entry<E> currentEntry; 1080 1081 /** Count of subsequent elements equal to current element */ 1082 private int laterCount; 1083 1084 /** Count of all elements equal to current element */ 1085 private int totalCount; 1086 1087 private boolean canRemove; 1088 1089 MultisetIteratorImpl(Multiset<E> multiset, Iterator<Entry<E>> entryIterator) { 1090 this.multiset = multiset; 1091 this.entryIterator = entryIterator; 1092 } 1093 1094 @Override 1095 public boolean hasNext() { 1096 return laterCount > 0 || entryIterator.hasNext(); 1097 } 1098 1099 @Override 1100 @ParametricNullness 1101 public E next() { 1102 if (!hasNext()) { 1103 throw new NoSuchElementException(); 1104 } 1105 if (laterCount == 0) { 1106 currentEntry = entryIterator.next(); 1107 totalCount = laterCount = currentEntry.getCount(); 1108 } 1109 laterCount--; 1110 canRemove = true; 1111 /* 1112 * requireNonNull is safe because laterCount starts at 0, forcing us to initialize 1113 * currentEntry above. After that, we never clear it. 1114 */ 1115 return requireNonNull(currentEntry).getElement(); 1116 } 1117 1118 @Override 1119 public void remove() { 1120 checkRemove(canRemove); 1121 if (totalCount == 1) { 1122 entryIterator.remove(); 1123 } else { 1124 /* 1125 * requireNonNull is safe because canRemove is set to true only after we initialize 1126 * currentEntry (which we never subsequently clear). 1127 */ 1128 multiset.remove(requireNonNull(currentEntry).getElement()); 1129 } 1130 totalCount--; 1131 canRemove = false; 1132 } 1133 } 1134 1135 static <E extends @Nullable Object> Spliterator<E> spliteratorImpl(Multiset<E> multiset) { 1136 Spliterator<Entry<E>> entrySpliterator = multiset.entrySet().spliterator(); 1137 return CollectSpliterators.flatMap( 1138 entrySpliterator, 1139 (Entry<E> entry) -> nCopies(entry.getCount(), entry.getElement()).spliterator(), 1140 Spliterator.SIZED 1141 | (entrySpliterator.characteristics() 1142 & (Spliterator.ORDERED | Spliterator.NONNULL | Spliterator.IMMUTABLE)), 1143 multiset.size()); 1144 } 1145 1146 /** An implementation of {@link Multiset#size}. */ 1147 static int linearTimeSizeImpl(Multiset<?> multiset) { 1148 long size = 0; 1149 for (Entry<?> entry : multiset.entrySet()) { 1150 size += entry.getCount(); 1151 } 1152 return Ints.saturatedCast(size); 1153 } 1154 1155 /** 1156 * Returns a copy of {@code multiset} as an {@link ImmutableMultiset} whose iteration order puts 1157 * the highest count first, with ties broken by the iteration order of the original multiset. 1158 * 1159 * @since 11.0 1160 */ 1161 public static <E> ImmutableMultiset<E> copyHighestCountFirst(Multiset<E> multiset) { 1162 @SuppressWarnings("unchecked") // generics+arrays 1163 // TODO(cpovirk): Consider storing an Entry<?> instead of Entry<E>. 1164 Entry<E>[] entries = multiset.entrySet().toArray((Entry<E>[]) new Entry<?>[0]); 1165 sort(entries, DecreasingCount.INSTANCE); 1166 return ImmutableMultiset.copyFromEntries(asList(entries)); 1167 } 1168 1169 private static final class DecreasingCount implements Comparator<Entry<?>> { 1170 static final Comparator<Entry<?>> INSTANCE = new DecreasingCount(); 1171 1172 @Override 1173 public int compare(Entry<?> entry1, Entry<?> entry2) { 1174 return entry2.getCount() - entry1.getCount(); // subtracting two nonnegative integers 1175 } 1176 } 1177 1178 /** 1179 * An {@link AbstractMultiset} with additional default implementations, some of them linear-time 1180 * implementations in terms of {@code elementSet} and {@code entrySet}. 1181 */ 1182 private abstract static class ViewMultiset<E extends @Nullable Object> 1183 extends AbstractMultiset<E> { 1184 @Override 1185 public int size() { 1186 return linearTimeSizeImpl(this); 1187 } 1188 1189 @Override 1190 public void clear() { 1191 elementSet().clear(); 1192 } 1193 1194 @Override 1195 public Iterator<E> iterator() { 1196 return iteratorImpl(this); 1197 } 1198 1199 @Override 1200 int distinctElements() { 1201 return elementSet().size(); 1202 } 1203 } 1204}