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