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