All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.landawn.abacus.util.Multiset Maven / Gradle / Ivy

/*
 * Copyright (c) 2015, Haiyang Li.
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.landawn.abacus.util;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.NoSuchElementException;
import java.util.Set;

import com.landawn.abacus.annotation.Internal;
import com.landawn.abacus.util.Fn.Suppliers;
import com.landawn.abacus.util.u.Optional;
import com.landawn.abacus.util.u.OptionalDouble;
import com.landawn.abacus.util.function.Function;
import com.landawn.abacus.util.function.IntFunction;
import com.landawn.abacus.util.function.Supplier;
import com.landawn.abacus.util.stream.EntryStream;
import com.landawn.abacus.util.stream.Stream;

/**
 * A collection that supports order-independent equality, like {@link Set}, but
 * may have duplicate elements.
 *
 * 

Elements of a Multiset that are equal to one another are referred to as * occurrences of the same single element. The total number of * occurrences of an element in a Multiset is called the count of that * element (the terms "frequency" and "multiplicity" are equivalent, but not * used in this API). Since the count of an element is represented as an {@code * int}, a Multiset may never contain more than {@link MutableInt#MAX_VALUE} * occurrences of any one element. * * @param * * @since 0.8 * * @author Haiyang Li */ public final class Multiset implements Iterable { private static final Comparator> cmpByCount = new Comparator>() { @Override public int compare(Entry a, Entry b) { return N.compare(a.getValue().value(), b.getValue().value()); } }; final Supplier> mapSupplier; final Map valueMap; public Multiset() { this(HashMap.class); } public Multiset(int initialCapacity) { this.mapSupplier = Suppliers.ofMap(); this.valueMap = new HashMap(initialCapacity); } public Multiset(final Collection c) { this(); addAll(c); } @SuppressWarnings("rawtypes") public Multiset(final Class valueMapType) { this(Maps.mapType2Supplier(valueMapType)); } @SuppressWarnings("rawtypes") public Multiset(final Supplier> mapSupplier) { this.mapSupplier = (Supplier) mapSupplier; this.valueMap = this.mapSupplier.get(); } /** * * @param valueMap The valueMap and this Multiset share the same data; any changes to one will appear in the other. */ @Internal Multiset(final Map valueMap) { this.mapSupplier = Maps.mapType2Supplier(valueMap.getClass()); this.valueMap = valueMap; } @SafeVarargs public static Multiset of(final T... a) { if (N.isNullOrEmpty(a)) { return new Multiset<>(); } final Multiset multiset = new Multiset<>(new HashMap(N.initHashCapacity(a.length))); for (T e : a) { multiset.add(e); } return multiset; } public static Multiset from(final Collection coll) { return new Multiset<>(coll); } public static Multiset from(final Map m) { if (N.isNullOrEmpty(m)) { return new Multiset(); } final Multiset multiset = new Multiset<>(Maps.newTargetMap(m)); multiset.setAll(m); return multiset; } /** * * @param e * @return the occurrences of the specified object. zero is returned if it's not in this set. */ public int get(final Object e) { final MutableInt count = valueMap.get(e); return count == null ? 0 : count.value(); } /** * * @param e * @param defaultValue * @return the occurrences of the specified object. the specified defaultValue is returned if it's not in this set. */ public int getOrDefault(final Object e, int defaultValue) { final MutableInt count = valueMap.get(e); return count == null ? defaultValue : count.value(); } /** * The element will be removed if the specified count is 0. * * @param e * @param occurrences * @return */ public int getAndSet(final T e, final int occurrences) { checkOccurrences(occurrences); final MutableInt count = valueMap.get(e); int result = count == null ? 0 : count.value(); if (occurrences == 0) { if (count != null) { valueMap.remove(e); } } else { if (count == null) { valueMap.put(e, MutableInt.of(occurrences)); } else { count.setValue(occurrences); } } return result; } /** * The element will be removed if the specified count is 0. * * @param e * @param occurrences * @return */ public int setAndGet(final T e, final int occurrences) { checkOccurrences(occurrences); final MutableInt count = valueMap.get(e); if (occurrences == 0) { if (count != null) { valueMap.remove(e); } } else { if (count == null) { valueMap.put(e, MutableInt.of(occurrences)); } else { count.setValue(occurrences); } } return occurrences; } /** * The element will be removed if the specified count is 0. * * @param e * @param occurrences * @return this Multiset. * @throws IllegalArgumentException if the occurrences of element is less than 0 */ public Multiset set(final T e, final int occurrences) { checkOccurrences(occurrences); if (occurrences == 0) { valueMap.remove(e); } else { final MutableInt count = valueMap.get(e); if (count == null) { valueMap.put(e, MutableInt.of(occurrences)); } else { count.setValue(occurrences); } } return this; } public Multiset setAll(final Collection c, final int occurrences) { checkOccurrences(occurrences); if (N.notNullOrEmpty(c)) { for (T e : c) { set(e, occurrences); } } return this; } /** * * @param m * @return this Multiset. * @throws IllegalArgumentException if the occurrences of element is less than 0. */ public Multiset setAll(final Map m) throws IllegalArgumentException { if (N.notNullOrEmpty(m)) { for (Map.Entry entry : m.entrySet()) { checkOccurrences(entry.getValue().intValue()); } for (Map.Entry entry : m.entrySet()) { set(entry.getKey(), entry.getValue().intValue()); } } return this; } /** * * @param m * @return this Multiset. * @throws IllegalArgumentException if the occurrences of element is less than 0. */ public Multiset setAll(final Multiset multiset) throws IllegalArgumentException { if (N.notNullOrEmpty(multiset)) { for (Map.Entry entry : multiset.valueMap.entrySet()) { set(entry.getKey(), entry.getValue().value()); } } return this; } public int occurrencesOf(final Object e) { return get(e); } public Optional> minOccurrences() { if (size() == 0) { return Optional.empty(); } final Iterator> it = valueMap.entrySet().iterator(); Map.Entry entry = it.next(); T minCountElement = entry.getKey(); int minCount = entry.getValue().value(); while (it.hasNext()) { entry = it.next(); if (entry.getValue().value() < minCount) { minCountElement = entry.getKey(); minCount = entry.getValue().value(); } } return Optional.of(Pair.of(minCountElement, minCount)); } public Optional> maxOccurrences() { if (size() == 0) { return Optional.empty(); } final Iterator> it = valueMap.entrySet().iterator(); Map.Entry entry = it.next(); T maxCountElement = entry.getKey(); int maxCount = entry.getValue().value(); while (it.hasNext()) { entry = it.next(); if (entry.getValue().value() > maxCount) { maxCountElement = entry.getKey(); maxCount = entry.getValue().value(); } } return Optional.of(Pair.of(maxCountElement, maxCount)); } public Optional, Integer>> allMinOccurrences() { if (size() == 0) { return Optional.empty(); } int min = Integer.MAX_VALUE; for (MutableInt e : valueMap.values()) { if (e.value() < min) { min = e.value(); } } final List res = new ArrayList<>(); for (Map.Entry entry : valueMap.entrySet()) { if (entry.getValue().value() == min) { res.add(entry.getKey()); } } return Optional.of(Pair.of(res, min)); } public Optional, Integer>> allMaxOccurrences() { if (size() == 0) { return Optional.empty(); } int max = Integer.MIN_VALUE; for (MutableInt e : valueMap.values()) { if (e.value() > max) { max = e.value(); } } final List res = new ArrayList<>(); for (Map.Entry entry : valueMap.entrySet()) { if (entry.getValue().value() == max) { res.add(entry.getKey()); } } return Optional.of(Pair.of(res, max)); } /** * * @return * @throws ArithmeticException if total occurrences overflows the maximum value of int. */ public long sumOfOccurrences() { long sum = 0; for (MutableInt count : valueMap.values()) { sum = Matth.addExact(sum, count.value()); } return sum; } public OptionalDouble averageOfOccurrences() { if (size() == 0) { return OptionalDouble.empty(); } final double sum = sumOfOccurrences(); return OptionalDouble.of(sum / size()); } /** * * @param e * @return always true * @throws IllegalArgumentException if the occurrences of element after this operation is bigger than Integer.MAX_VALUE. */ public boolean add(final T e) throws IllegalArgumentException { return add(e, 1); } /** * * @param e * @param occurrences * @return true if the specified occurrences is bigger than 0. * @throws IllegalArgumentException if the occurrences of element after this operation is bigger than Integer.MAX_VALUE. */ public boolean add(final T e, final int occurrences) throws IllegalArgumentException { checkOccurrences(occurrences); MutableInt count = valueMap.get(e); if (count != null && occurrences > (Integer.MAX_VALUE - count.value())) { throw new IllegalArgumentException("The total count is out of the bound of int"); } if (count == null) { if (occurrences > 0) { count = MutableInt.of(occurrences); valueMap.put(e, count); } } else { count.add(occurrences); } return occurrences > 0; } /** * * @param e * @return true if the specified element is absent. * @throws IllegalArgumentException */ public boolean addIfAbsent(final T e) throws IllegalArgumentException { return addIfAbsent(e, 1); } /** * * @param e * @param occurrences * @return true if the specified element is absent and occurrences is bigger than 0. * @throws IllegalArgumentException */ public boolean addIfAbsent(final T e, final int occurrences) throws IllegalArgumentException { checkOccurrences(occurrences); MutableInt count = valueMap.get(e); if (count == null && occurrences > 0) { count = MutableInt.of(occurrences); valueMap.put(e, count); return true; } return false; } public int addAndGet(final T e) { return addAndGet(e, 1); } public int addAndGet(final T e, final int occurrences) { checkOccurrences(occurrences); MutableInt count = valueMap.get(e); if (count != null && occurrences > (Integer.MAX_VALUE - count.value())) { throw new IllegalArgumentException("The total count is out of the bound of int"); } if (count == null) { if (occurrences > 0) { count = MutableInt.of(occurrences); valueMap.put(e, count); } } else { count.add(occurrences); } return count == null ? 0 : count.value(); } public int getAndAdd(final T e) { return getAndAdd(e, 1); } public int getAndAdd(final T e, final int occurrences) { checkOccurrences(occurrences); MutableInt count = valueMap.get(e); if (count != null && occurrences > (Integer.MAX_VALUE - count.value())) { throw new IllegalArgumentException("The total count is out of the bound of int"); } final int result = count == null ? 0 : count.value(); if (count == null) { if (occurrences > 0) { count = MutableInt.of(occurrences); valueMap.put(e, count); } } else { count.add(occurrences); } return result; } /** * * @param c * @throws IllegalArgumentException if the occurrences of element after this operation is bigger than Integer.MAX_VALUE. */ public boolean addAll(final Collection c) throws IllegalArgumentException { if (N.isNullOrEmpty(c)) { return false; } return addAll(c, 1); } /** * * @param c * @param occurrences * @throws IllegalArgumentException if the occurrences of element after this operation is bigger than Integer.MAX_VALUE. */ public boolean addAll(final Collection c, final int occurrences) throws IllegalArgumentException { checkOccurrences(occurrences); if (N.isNullOrEmpty(c) || occurrences == 0) { return false; } for (T e : c) { add(e, occurrences); } return occurrences > 0; } /** * * @param m * @throws IllegalArgumentException if the occurrences of element after this operation is bigger than Integer.MAX_VALUE. */ public boolean addAll(final Map m) throws IllegalArgumentException { if (N.isNullOrEmpty(m)) { return false; } for (Map.Entry entry : m.entrySet()) { checkOccurrences(entry.getValue().intValue()); } boolean result = false; for (Map.Entry entry : m.entrySet()) { if (result == false) { result = add(entry.getKey(), entry.getValue().intValue()); } else { add(entry.getKey(), entry.getValue().intValue()); } } return result; } /** * * @param m * @throws IllegalArgumentException if the occurrences of element is less than 0. */ public boolean addAll(final Multiset multiset) throws IllegalArgumentException { if (N.isNullOrEmpty(multiset)) { return false; } for (Map.Entry entry : multiset.valueMap.entrySet()) { add(entry.getKey(), entry.getValue().value()); } return true; } public boolean contains(final Object o) { return valueMap.containsKey(o); } public boolean containsAll(final Collection c) { return valueMap.keySet().containsAll(c); } /** * Remove one occurrence from the specified elements. * The element will be removed from this Multiset if the occurrences equals to or less than 0 after the operation. * * @param e * @param occurrences * @return */ public boolean remove(final Object e) { return remove(e, 1); } /** * Remove the specified occurrences from the specified element. * The element will be removed from this Multiset if the occurrences equals to or less than 0 after the operation. * * @param e * @param occurrences * @return */ public boolean remove(final Object e, final int occurrences) { checkOccurrences(occurrences); final MutableInt count = valueMap.get(e); if (count == null) { return false; } else { count.subtract(occurrences); if (count.value() <= 0) { valueMap.remove(e); } return occurrences > 0; } } public int removeAndGet(final Object e) { return removeAndGet(e, 1); } public int removeAndGet(final Object e, final int occurrences) { checkOccurrences(occurrences); final MutableInt count = valueMap.get(e); if (count == null) { return 0; } else { count.subtract(occurrences); if (count.value() <= 0) { valueMap.remove(e); } return count.value() > 0 ? count.value() : 0; } } public int getAndRemove(final Object e) { return getAndRemove(e, 1); } public int getAndRemove(final Object e, final int occurrences) { checkOccurrences(occurrences); final MutableInt count = valueMap.get(e); final int result = count == null ? 0 : count.value(); if (count != null) { count.subtract(occurrences); if (count.value() <= 0) { valueMap.remove(e); } } return result; } /** * * @param e * @return the occurrences of the specified element before it's removed. */ public int removeAllOccurrences(final Object e) { final MutableInt count = valueMap.remove(e); return count == null ? 0 : count.value(); } public boolean removeAllOccurrencesIf(Try.Predicate predicate) throws E { Set removingKeys = null; for (T key : this.valueMap.keySet()) { if (predicate.test(key)) { if (removingKeys == null) { removingKeys = new HashSet<>(); } removingKeys.add(key); } } if (N.isNullOrEmpty(removingKeys)) { return false; } removeAll(removingKeys); return true; } public boolean removeAllOccurrencesIf(Try.BiPredicate predicate) throws E { Set removingKeys = null; for (Map.Entry entry : this.valueMap.entrySet()) { if (predicate.test(entry.getKey(), entry.getValue().value())) { if (removingKeys == null) { removingKeys = new HashSet<>(); } removingKeys.add(entry.getKey()); } } if (N.isNullOrEmpty(removingKeys)) { return false; } removeAll(removingKeys); return true; } public boolean removeIf(final int occurrences, Try.Predicate predicate) throws E { checkOccurrences(occurrences); Set removingKeys = null; for (T key : this.valueMap.keySet()) { if (predicate.test(key)) { if (removingKeys == null) { removingKeys = new HashSet<>(); } removingKeys.add(key); } } if (N.isNullOrEmpty(removingKeys)) { return false; } removeAll(removingKeys, occurrences); return true; } public boolean removeIf(final int occurrences, Try.BiPredicate predicate) throws E { checkOccurrences(occurrences); Set removingKeys = null; for (Map.Entry entry : this.valueMap.entrySet()) { if (predicate.test(entry.getKey(), entry.getValue().value())) { if (removingKeys == null) { removingKeys = new HashSet<>(); } removingKeys.add(entry.getKey()); } } if (N.isNullOrEmpty(removingKeys)) { return false; } removeAll(removingKeys, occurrences); return true; } /** * Removes all of this Multiset's elements that are also contained in the * specified collection (optional operation). After this call returns, * this Multiset will contain no elements in common with the specified * collection. This method ignores how often any element might appear in * {@code c}, and only cares whether or not an element appears at all. * * @param c * @return true if this set changed as a result of the call * @see Collection#removeAll(Collection) */ public boolean removeAll(final Collection c) { if (N.isNullOrEmpty(c)) { return false; } boolean result = false; for (Object e : c) { if (result == false) { result = valueMap.remove(e) != null; } else { valueMap.remove(e); } } return result; } /** * Remove the specified occurrences from the specified elements. * The elements will be removed from this set if the occurrences equals to or less than 0 after the operation. * * @param c * @param occurrences * the occurrences to remove if the element is in the specified collection c. * @return true if this set changed as a result of the call */ public boolean removeAll(final Collection c, final int occurrences) { checkOccurrences(occurrences); if (N.isNullOrEmpty(c) || occurrences == 0) { return false; } boolean result = false; for (Object e : c) { if (result == false) { result = remove(e, occurrences); } else { remove(e, occurrences); } } return result; } /** * * @param m * @return */ public boolean removeAll(final Map m) { if (N.isNullOrEmpty(m)) { return false; } for (Map.Entry entry : m.entrySet()) { checkOccurrences(entry.getValue().intValue()); } boolean result = false; for (Map.Entry entry : m.entrySet()) { if (result == false) { result = remove(entry.getKey(), entry.getValue().intValue()); } else { remove(entry.getKey(), entry.getValue().intValue()); } } return result; } /** * * @param m */ public boolean removeAll(final Multiset multiset) throws IllegalArgumentException { if (N.isNullOrEmpty(multiset)) { return false; } for (Map.Entry entry : multiset.valueMap.entrySet()) { remove(entry.getKey(), entry.getValue().value()); } return true; } public boolean replaceIf(Try.Predicate predicate, final int newOccurrences) throws E { checkOccurrences(newOccurrences); boolean modified = false; if (newOccurrences == 0) { final List keysToRemove = new ArrayList<>(); for (T key : valueMap.keySet()) { if (predicate.test(key)) { keysToRemove.add(key); } } if (keysToRemove.size() > 0) { for (T key : keysToRemove) { valueMap.remove(key); } modified = true; } } else { for (Map.Entry entry : valueMap.entrySet()) { if (predicate.test(entry.getKey())) { entry.getValue().setValue(newOccurrences); modified = true; } } } return modified; } public boolean replaceIf(Try.BiPredicate predicate, final int newOccurrences) throws E { checkOccurrences(newOccurrences); boolean modified = false; if (newOccurrences == 0) { final List keysToRemove = new ArrayList<>(); for (Map.Entry entry : valueMap.entrySet()) { if (predicate.test(entry.getKey(), entry.getValue().value())) { keysToRemove.add(entry.getKey()); } } if (keysToRemove.size() > 0) { for (T key : keysToRemove) { valueMap.remove(key); } modified = true; } } else { for (Map.Entry entry : valueMap.entrySet()) { if (predicate.test(entry.getKey(), entry.getValue().value())) { entry.getValue().setValue(newOccurrences); modified = true; } } } return modified; } /** * The associated elements will be removed if zero or negative occurrences are returned by the specified function. * * @param function */ public void replaceAll(Try.BiFunction function) throws E { List keyToRemove = null; Integer newVal = null; for (Map.Entry entry : this.valueMap.entrySet()) { newVal = function.apply(entry.getKey(), entry.getValue().value()); if (newVal == null || newVal.intValue() <= 0) { if (keyToRemove == null) { keyToRemove = new ArrayList<>(); } keyToRemove.add(entry.getKey()); } else { entry.getValue().setValue(newVal); } } if (N.notNullOrEmpty(keyToRemove)) { for (T key : keyToRemove) { valueMap.remove(key); } } } /** * Retains only the elements in this collection that are contained in the * specified collection (optional operation). In other words, removes from * this collection all of its elements that are not contained in the * specified collection. * * @param c * @return true if this set changed as a result of the call * @see Collection#retainAll(Collection) */ public boolean retainAll(final Collection c) { if (N.isNullOrEmpty(c)) { boolean result = size() > 0; clear(); return result; } Set others = null; for (T e : valueMap.keySet()) { if (!c.contains(e)) { if (others == null) { others = new HashSet<>(valueMap.size()); } others.add(e); } } return N.isNullOrEmpty(others) ? false : removeAll(others, Integer.MAX_VALUE); } public Multiset copy() { final Multiset copy = new Multiset(mapSupplier); copy.addAll(this); return copy; } public Set elements() { return ImmutableSet.of(valueMap.keySet()); } public int size() { return valueMap.size(); } public boolean isEmpty() { return valueMap.isEmpty(); } public void clear() { valueMap.clear(); } @Override public Iterator iterator() { return valueMap.keySet().iterator(); } // public Set> entrySet() { // return valueMap.entrySet(); // } public Object[] toArray() { return valueMap.keySet().toArray(); } public A[] toArray(final A[] a) { return valueMap.keySet().toArray(a); } public Map toMap() { final Map result = Maps.newOrderingMap(valueMap); for (Map.Entry entry : valueMap.entrySet()) { result.put(entry.getKey(), entry.getValue().value()); } return result; } public > M toMap(final IntFunction supplier) { final M result = supplier.apply(size()); for (Map.Entry entry : valueMap.entrySet()) { result.put(entry.getKey(), entry.getValue().value()); } return result; } @SuppressWarnings("rawtypes") public Map toMapSortedByOccurrences() { return toMapSortedBy((Comparator) cmpByCount); } public Map toMapSortedByOccurrences(final Comparator cmp) { return toMapSortedBy(new Comparator>() { @Override public int compare(Entry o1, Entry o2) { return cmp.compare(o1.getValue().value(), o2.getValue().value()); } }); } public Map toMapSortedByKey(final Comparator cmp) { return toMapSortedBy(new Comparator>() { @Override public int compare(Entry o1, Entry o2) { return cmp.compare(o1.getKey(), o2.getKey()); } }); } Map toMapSortedBy(final Comparator> cmp) { if (N.isNullOrEmpty(valueMap)) { return new LinkedHashMap<>(); } final Map.Entry[] entries = valueMap.entrySet().toArray(new Map.Entry[size()]); Arrays.sort(entries, cmp); final Map sortedValues = new LinkedHashMap<>(N.initHashCapacity(size())); for (Map.Entry entry : entries) { sortedValues.put(entry.getKey(), entry.getValue().value()); } return sortedValues; } public ImmutableMap toImmutableMap() { return ImmutableMap.of(toMap()); } public ImmutableMap toImmutableMap(final IntFunction> mapSupplier) { return ImmutableMap.of(toMap(mapSupplier)); } // It won't work. // public Multiset synchronizedd() { // return new Multiset<>(Collections.synchronizedMap(valueMap)); // } /** * * @return a list with all elements, each of them is repeated with the occurrences in this Multiset */ public List flatten() { final long totalOccurrences = sumOfOccurrences(); if (totalOccurrences > Integer.MAX_VALUE) { throw new RuntimeException("The total occurrences(" + totalOccurrences + ") is bigger than the max value of int."); } final Object[] a = new Object[(int) totalOccurrences]; int fromIndex = 0; int toIndex = 0; for (Map.Entry entry : valueMap.entrySet()) { toIndex = fromIndex + entry.getValue().value(); Arrays.fill(a, fromIndex, toIndex, entry.getKey()); fromIndex = toIndex; } return N.asList((T[]) a); } public Multiset filter(Try.Predicate filter) throws E { final Multiset result = new Multiset<>(mapSupplier.get()); for (Map.Entry entry : valueMap.entrySet()) { if (filter.test(entry.getKey())) { result.set(entry.getKey(), entry.getValue().intValue()); } } return result; } public Multiset filter(Try.BiPredicate filter) throws E { final Multiset result = new Multiset<>(mapSupplier.get()); for (Map.Entry entry : valueMap.entrySet()) { if (filter.test(entry.getKey(), entry.getValue().intValue())) { result.set(entry.getKey(), entry.getValue().intValue()); } } return result; } public void forEach(final Try.Consumer action) throws E { N.checkArgNotNull(action); for (T e : valueMap.keySet()) { action.accept(e); } } public void forEach(final Try.ObjIntConsumer action) throws E { N.checkArgNotNull(action); for (Map.Entry entry : valueMap.entrySet()) { action.accept(entry.getKey(), entry.getValue().value()); } } /** * The implementation is equivalent to performing the following steps for this Multiset: * *

     * final int oldValue = get(e);
     * 
     * if (oldValue > 0) {
     *     return oldValue;
     * }
     * 
     * final int newValue = mappingFunction.apply(e);
     * 
     * if (newValue > 0) {
     *     set(e, newValue);
     * }
     * 
     * return newValue;
     * 
* * @param e * @param mappingFunction * @return */ public int computeIfAbsent(T e, Try.Function mappingFunction) throws E { N.checkArgNotNull(mappingFunction); final int oldValue = get(e); if (oldValue > 0) { return oldValue; } final int newValue = mappingFunction.apply(e); if (newValue > 0) { set(e, newValue); } return newValue; } /** * The implementation is equivalent to performing the following steps for this Multiset: * *
 
     * final int oldValue = get(e);
     * 
     * if (oldValue == 0) {
     *     return oldValue;
     * }
     * 
     * final int newValue = remappingFunction.apply(e, oldValue);
     * 
     * if (newValue > 0) {
     *     set(e, newValue);
     * } else {
     *     remove(e);
     * }
     * 
     * return newValue;
     * 
* * @param e * @param remappingFunction * @return */ public int computeIfPresent(T e, Try.BiFunction remappingFunction) throws E { N.checkArgNotNull(remappingFunction); final int oldValue = get(e); if (oldValue == 0) { return oldValue; } final int newValue = remappingFunction.apply(e, oldValue); if (newValue > 0) { set(e, newValue); } else { remove(e); } return newValue; } /** * The implementation is equivalent to performing the following steps for this Multiset: * *
     * final int oldValue = get(key);
     * final int newValue = remappingFunction.apply(key, oldValue);
     * 
     * if (newValue > 0) {
     *     set(key, newValue);
     * } else {
     *     if (oldValue > 0) {
     *         remove(key);
     *     }
     * }
     * 
     * return newValue;
     * 
* * @param key * @param remappingFunction * @return */ public int compute(T key, Try.BiFunction remappingFunction) throws E { N.checkArgNotNull(remappingFunction); final int oldValue = get(key); final int newValue = remappingFunction.apply(key, oldValue); if (newValue > 0) { set(key, newValue); } else { if (oldValue > 0) { remove(key); } } return newValue; } /** * The implementation is equivalent to performing the following steps for this Multiset: * *
     * int oldValue = get(key);
     * int newValue = (oldValue == 0) ? value : remappingFunction.apply(oldValue, value);
     * 
     * if (newValue > 0) {
     *     set(key, newValue);
     * } else {
     *     if (oldValue > 0) {
     *         remove(key);
     *     }
     * }
     * 
     * return newValue;
     * 
* * @param key * @param value * @param remappingFunction * @return */ public int merge(T key, int value, Try.BiFunction remappingFunction) throws E { N.checkArgNotNull(remappingFunction); N.checkArgNotNull(value); int oldValue = get(key); int newValue = (oldValue == 0) ? value : remappingFunction.apply(oldValue, value); if (newValue > 0) { set(key, newValue); } else { if (oldValue > 0) { remove(key); } } return newValue; } public Stream stream() { return Stream.of(valueMap.keySet()); } public Stream flatStream() { final Iterator> entryIter = valueMap.entrySet().iterator(); final Iterator iter = new ObjIterator() { private Map.Entry entry = null; private T element = null; private int count = 0; private int cnt = 0; @Override public boolean hasNext() { if (cnt >= count) { while (cnt >= count && entryIter.hasNext()) { entry = entryIter.next(); element = entry.getKey(); count = entry.getValue().value(); cnt = 0; } } return cnt < count; } @Override public T next() { if (hasNext() == false) { throw new NoSuchElementException(); } cnt++; return element; } }; return Stream.of(iter); } private static final Function TO_INT = new Function() { @Override public Integer apply(MutableInt t) { return t.value(); } }; public EntryStream entryStream() { return EntryStream.of(valueMap).mapValue(TO_INT); } public R apply(Try.Function, R, E> func) throws E { return func.apply(this); } public Optional applyIfNotEmpty(Try.Function, R, E> func) throws E { return isEmpty() ? Optional. empty() : Optional.ofNullable(func.apply(this)); } public void accept(Try.Consumer, E> action) throws E { action.accept(this); } public void acceptIfNotEmpty(Try.Consumer, E> action) throws E { if (size() > 0) { action.accept(this); } } @Override public int hashCode() { return valueMap.hashCode(); } @Override public boolean equals(final Object obj) { return obj == this || (obj instanceof Multiset && valueMap.equals(((Multiset) obj).valueMap)); } @Override public String toString() { return valueMap.toString(); } private static void checkOccurrences(final int occurrences) { if (occurrences < 0) { throw new IllegalArgumentException("The specified 'occurrences' can not be negative"); } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy