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