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