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

com.gs.collections.impl.bag.mutable.HashBag Maven / Gradle / Ivy

Go to download

GS Collections is a collections framework for Java. It has JDK-compatible List, Set and Map implementations with a rich API and set of utility classes that work with any JDK compatible Collections, Arrays, Maps or Strings. The iteration protocol was inspired by the Smalltalk collection framework.

There is a newer version: 7.0.3
Show newest version
/*
 * Copyright 2014 Goldman Sachs.
 *
 * 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.gs.collections.impl.bag.mutable;

import java.io.Externalizable;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.util.Arrays;
import java.util.Collection;
import java.util.Comparator;
import java.util.Iterator;
import java.util.NoSuchElementException;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.TimeUnit;

import com.gs.collections.api.LazyIterable;
import com.gs.collections.api.annotation.Beta;
import com.gs.collections.api.bag.Bag;
import com.gs.collections.api.bag.ImmutableBag;
import com.gs.collections.api.bag.MutableBag;
import com.gs.collections.api.bag.ParallelUnsortedBag;
import com.gs.collections.api.bag.primitive.MutableBooleanBag;
import com.gs.collections.api.bag.primitive.MutableByteBag;
import com.gs.collections.api.bag.primitive.MutableCharBag;
import com.gs.collections.api.bag.primitive.MutableDoubleBag;
import com.gs.collections.api.bag.primitive.MutableFloatBag;
import com.gs.collections.api.bag.primitive.MutableIntBag;
import com.gs.collections.api.bag.primitive.MutableLongBag;
import com.gs.collections.api.bag.primitive.MutableShortBag;
import com.gs.collections.api.block.function.Function;
import com.gs.collections.api.block.function.Function0;
import com.gs.collections.api.block.function.Function2;
import com.gs.collections.api.block.function.primitive.BooleanFunction;
import com.gs.collections.api.block.function.primitive.ByteFunction;
import com.gs.collections.api.block.function.primitive.CharFunction;
import com.gs.collections.api.block.function.primitive.DoubleFunction;
import com.gs.collections.api.block.function.primitive.FloatFunction;
import com.gs.collections.api.block.function.primitive.IntFunction;
import com.gs.collections.api.block.function.primitive.LongFunction;
import com.gs.collections.api.block.function.primitive.ShortFunction;
import com.gs.collections.api.block.predicate.Predicate;
import com.gs.collections.api.block.predicate.Predicate2;
import com.gs.collections.api.block.predicate.primitive.IntPredicate;
import com.gs.collections.api.block.predicate.primitive.ObjectIntPredicate;
import com.gs.collections.api.block.procedure.Procedure;
import com.gs.collections.api.block.procedure.Procedure2;
import com.gs.collections.api.block.procedure.primitive.ObjectIntProcedure;
import com.gs.collections.api.list.MutableList;
import com.gs.collections.api.map.MutableMap;
import com.gs.collections.api.map.primitive.MutableObjectIntMap;
import com.gs.collections.api.multimap.MutableMultimap;
import com.gs.collections.api.partition.bag.PartitionMutableBag;
import com.gs.collections.api.set.MutableSet;
import com.gs.collections.api.tuple.Pair;
import com.gs.collections.api.tuple.primitive.ObjectIntPair;
import com.gs.collections.impl.Counter;
import com.gs.collections.impl.bag.mutable.primitive.BooleanHashBag;
import com.gs.collections.impl.bag.mutable.primitive.ByteHashBag;
import com.gs.collections.impl.bag.mutable.primitive.CharHashBag;
import com.gs.collections.impl.bag.mutable.primitive.DoubleHashBag;
import com.gs.collections.impl.bag.mutable.primitive.FloatHashBag;
import com.gs.collections.impl.bag.mutable.primitive.IntHashBag;
import com.gs.collections.impl.bag.mutable.primitive.LongHashBag;
import com.gs.collections.impl.bag.mutable.primitive.ShortHashBag;
import com.gs.collections.impl.block.factory.Predicates2;
import com.gs.collections.impl.block.factory.primitive.IntToIntFunctions;
import com.gs.collections.impl.block.procedure.CollectionAddProcedure;
import com.gs.collections.impl.block.procedure.MultimapEachPutProcedure;
import com.gs.collections.impl.block.procedure.MultimapPutProcedure;
import com.gs.collections.impl.collection.AbstractMutableBag;
import com.gs.collections.impl.factory.Bags;
import com.gs.collections.impl.lazy.AbstractLazyIterable;
import com.gs.collections.impl.lazy.parallel.AbstractBatch;
import com.gs.collections.impl.lazy.parallel.bag.AbstractParallelUnsortedBag;
import com.gs.collections.impl.lazy.parallel.bag.CollectUnsortedBagBatch;
import com.gs.collections.impl.lazy.parallel.bag.RootUnsortedBagBatch;
import com.gs.collections.impl.lazy.parallel.bag.SelectUnsortedBagBatch;
import com.gs.collections.impl.lazy.parallel.bag.UnsortedBagBatch;
import com.gs.collections.impl.list.mutable.FastList;
import com.gs.collections.impl.map.mutable.UnifiedMap;
import com.gs.collections.impl.map.mutable.primitive.ObjectIntHashMap;
import com.gs.collections.impl.multimap.bag.HashBagMultimap;
import com.gs.collections.impl.partition.bag.PartitionHashBag;
import com.gs.collections.impl.set.mutable.UnifiedSet;
import com.gs.collections.impl.utility.ArrayIterate;
import com.gs.collections.impl.utility.Iterate;

/**
 * A HashBag is a MutableBag which uses a Map as its underlying data store.  Each key in the Map represents some item,
 * and the value in the map represents the current number of occurrences of that item.
 *
 * @since 1.0
 */
public class HashBag
        extends AbstractMutableBag
        implements Externalizable, MutableBag
{
    private static final long serialVersionUID = 1L;

    private MutableObjectIntMap items;
    private int size;

    public HashBag()
    {
        this.items = ObjectIntHashMap.newMap();
    }

    public HashBag(int size)
    {
        this.items = new ObjectIntHashMap(size);
    }

    private HashBag(MutableObjectIntMap map)
    {
        this.items = map;
        this.size = (int) map.sum();
    }

    public static  HashBag newBag()
    {
        return new HashBag();
    }

    public static  HashBag newBag(int size)
    {
        return new HashBag(size);
    }

    public static  HashBag newBag(Bag source)
    {
        final HashBag result = HashBag.newBag();
        source.forEachWithOccurrences(new ObjectIntProcedure()
        {
            public void value(E each, int occurrences)
            {
                result.addOccurrences(each, occurrences);
            }
        });
        return result;
    }

    public static  HashBag newBag(Iterable source)
    {
        return HashBag.newBagWith((E[]) Iterate.toArray(source));
    }

    public static  HashBag newBagWith(E... elements)
    {
        HashBag result = HashBag.newBag();
        ArrayIterate.addAllTo(elements, result);
        return result;
    }

    public void addOccurrences(T item, int occurrences)
    {
        if (occurrences < 0)
        {
            throw new IllegalArgumentException("Cannot add a negative number of occurrences");
        }
        if (occurrences > 0)
        {
            this.items.updateValue(item, 0, IntToIntFunctions.add(occurrences));
            this.size += occurrences;
        }
    }

    @Override
    public boolean equals(Object other)
    {
        if (this == other)
        {
            return true;
        }
        if (!(other instanceof Bag))
        {
            return false;
        }
        final Bag bag = (Bag) other;
        if (this.sizeDistinct() != bag.sizeDistinct())
        {
            return false;
        }

        return this.items.keyValuesView().allSatisfy(new Predicate>()
        {
            public boolean accept(ObjectIntPair each)
            {
                return bag.occurrencesOf(each.getOne()) == each.getTwo();
            }
        });
    }

    public int sizeDistinct()
    {
        return this.items.size();
    }

    @Override
    public int hashCode()
    {
        final Counter counter = new Counter();
        this.items.forEachKeyValue(new ObjectIntProcedure()
        {
            public void value(T item, int count)
            {
                counter.add((item == null ? 0 : item.hashCode()) ^ count);
            }
        });
        return counter.getCount();
    }

    public int occurrencesOf(Object item)
    {
        return this.items.get(item);
    }

    public void forEachWithOccurrences(final ObjectIntProcedure objectIntProcedure)
    {
        this.items.forEachKeyValue(new ObjectIntProcedure()
        {
            public void value(T item, int count)
            {
                objectIntProcedure.value(item, count);
            }
        });
    }

    public MutableBag selectByOccurrences(final IntPredicate predicate)
    {
        MutableObjectIntMap map = this.items.select(new ObjectIntPredicate()
        {
            public boolean accept(T each, int occurrences)
            {
                return predicate.accept(occurrences);
            }
        });
        return new HashBag(map);
    }

    public MutableMap toMapOfItemToCount()
    {
        final MutableMap map = UnifiedMap.newMap(this.items.size());
        this.forEachWithOccurrences(new ObjectIntProcedure()
        {
            public void value(T item, int count)
            {
                map.put(item, count);
            }
        });
        return map;
    }

    public String toStringOfItemToCount()
    {
        return this.items.toString();
    }

    @Override
    public boolean remove(Object item)
    {
        int newValue = this.items.updateValue((T) item, 0, IntToIntFunctions.decrement());
        if (newValue <= 0)
        {
            this.items.removeKey((T) item);
            if (newValue == -1)
            {
                return false;
            }
        }
        this.size--;
        return true;
    }

    @Override
    public boolean removeAll(Collection collection)
    {
        return this.removeAllIterable(collection);
    }

    @Override
    public boolean retainAll(Collection collection)
    {
        return this.retainAllIterable(collection);
    }

    public void clear()
    {
        this.items.clear();
        this.size = 0;
    }

    @Override
    public boolean isEmpty()
    {
        return this.items.isEmpty();
    }

    public void writeExternal(ObjectOutput out) throws IOException
    {
        ((ObjectIntHashMap) this.items).writeExternal(out);
    }

    public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException
    {
        this.items = new ObjectIntHashMap();
        ((ObjectIntHashMap) this.items).readExternal(in);
        this.size = (int) this.items.sum();
    }

    public void forEach(final Procedure procedure)
    {
        this.items.forEachKeyValue(new ObjectIntProcedure()
        {
            public void value(T key, int count)
            {
                for (int i = 0; i < count; i++)
                {
                    procedure.value(key);
                }
            }
        });
    }

    @Override
    public void forEachWithIndex(final ObjectIntProcedure objectIntProcedure)
    {
        final Counter index = new Counter();
        this.items.forEachKeyValue(new ObjectIntProcedure()
        {
            public void value(T key, int count)
            {
                for (int i = 0; i < count; i++)
                {
                    objectIntProcedure.value(key, index.getCount());
                    index.increment();
                }
            }
        });
    }

    @Override
    public 

void forEachWith(final Procedure2 procedure, final P parameter) { this.items.forEachKeyValue(new ObjectIntProcedure() { public void value(T key, int count) { for (int i = 0; i < count; i++) { procedure.value(key, parameter); } } }); } public Iterator iterator() { return new InternalIterator(); } public boolean removeOccurrences(Object item, int occurrences) { if (occurrences < 0) { throw new IllegalArgumentException("Cannot remove a negative number of occurrences"); } if (occurrences == 0) { return false; } int newValue = this.items.updateValue((T) item, 0, IntToIntFunctions.subtract(occurrences)); if (newValue <= 0) { this.size -= occurrences + newValue; this.items.remove((T) item); return newValue + occurrences != 0; } this.size -= occurrences; return true; } public boolean setOccurrences(T item, int occurrences) { if (occurrences < 0) { throw new IllegalArgumentException("Cannot set a negative number of occurrences"); } int originalOccurrences = this.items.get(item); if (originalOccurrences == occurrences) { return false; } if (occurrences == 0) { this.items.remove(item); } else { this.items.put(item, occurrences); } this.size -= originalOccurrences - occurrences; return true; } public HashBag without(T element) { this.remove(element); return this; } public MutableBag newEmpty() { return HashBag.newBag(); } public MutableBag collectWith( final Function2 function, final P parameter) { final HashBag result = HashBag.newBag(this.items.size()); this.forEachWithOccurrences(new ObjectIntProcedure() { public void value(T each, int occurrences) { result.addOccurrences(function.value(each, parameter), occurrences); } }); return result; } public HashBag with(T element) { this.add(element); return this; } public SynchronizedBag asSynchronized() { return new SynchronizedBag(this); } public HashBag withAll(Iterable iterable) { this.addAllIterable(iterable); return this; } public HashBag withoutAll(Iterable iterable) { this.removeAllIterable(iterable); return this; } public

MutableBag selectWith(final Predicate2 predicate, final P parameter) { final MutableBag result = HashBag.newBag(); this.forEachWithOccurrences(new ObjectIntProcedure() { public void value(T each, int occurrences) { if (predicate.accept(each, parameter)) { result.addOccurrences(each, occurrences); } } }); return result; } public

MutableBag rejectWith(final Predicate2 predicate, final P parameter) { final MutableBag result = HashBag.newBag(); this.forEachWithOccurrences(new ObjectIntProcedure() { public void value(T each, int index) { if (!predicate.accept(each, parameter)) { result.addOccurrences(each, index); } } }); return result; } @Override public void removeIf(Predicate predicate) { for (Iterator iterator = this.items.keySet().iterator(); iterator.hasNext(); ) { T key = iterator.next(); if (predicate.accept(key)) { this.size -= this.items.get(key); iterator.remove(); } } } @Override public

void removeIfWith(Predicate2 predicate, P parameter) { for (Iterator iterator = this.items.keySet().iterator(); iterator.hasNext(); ) { T key = iterator.next(); if (predicate.accept(key, parameter)) { this.size -= this.items.get(key); iterator.remove(); } } } @Override public

T detectWith(final Predicate2 predicate, final P parameter) { return this.items.keysView().detect(new Predicate() { public boolean accept(T each) { return predicate.accept(each, parameter); } }); } @Override public

T detectWithIfNone( final Predicate2 predicate, final P parameter, Function0 function) { return this.items.keysView().detectIfNone(new Predicate() { public boolean accept(T each) { return predicate.accept(each, parameter); } }, function); } @Override public

int countWith(final Predicate2 predicate, final P parameter) { final Counter result = new Counter(); this.forEachWithOccurrences(new ObjectIntProcedure() { public void value(T each, int occurrences) { if (predicate.accept(each, parameter)) { result.add(occurrences); } } }); return result.getCount(); } @Override public

boolean anySatisfyWith(final Predicate2 predicate, final P parameter) { return this.items.keysView().anySatisfy(new Predicate() { public boolean accept(T each) { return predicate.accept(each, parameter); } }); } @Override public

boolean allSatisfyWith(final Predicate2 predicate, final P parameter) { return this.items.keysView().allSatisfy(new Predicate() { public boolean accept(T each) { return predicate.accept(each, parameter); } }); } @Override public

boolean noneSatisfyWith(final Predicate2 predicate, final P parameter) { return this.items.keysView().noneSatisfy(new Predicate() { public boolean accept(T each) { return predicate.accept(each, parameter); } }); } public UnmodifiableBag asUnmodifiable() { return UnmodifiableBag.of(this); } public ImmutableBag toImmutable() { return Bags.immutable.withAll(this); } @Override public boolean removeAllIterable(Iterable iterable) { int oldSize = this.size; for (Object each : iterable) { int removed = this.items.removeKeyIfAbsent((T) each, 0); this.size -= removed; } return this.size != oldSize; } @Override public boolean retainAllIterable(Iterable iterable) { int oldSize = this.size; this.removeIfWith(Predicates2.notIn(), UnifiedSet.newSet(iterable)); return this.size != oldSize; } public int size() { return this.size; } @Override public boolean contains(Object o) { return this.items.containsKey(o); } public MutableBag select(final Predicate predicate) { final MutableBag result = HashBag.newBag(); this.forEachWithOccurrences(new ObjectIntProcedure() { public void value(T each, int occurrences) { if (predicate.accept(each)) { result.addOccurrences(each, occurrences); } } }); return result; } public PartitionMutableBag partition(final Predicate predicate) { final PartitionMutableBag result = new PartitionHashBag(); this.forEachWithOccurrences(new ObjectIntProcedure() { public void value(T each, int index) { MutableBag bucket = predicate.accept(each) ? result.getSelected() : result.getRejected(); bucket.addOccurrences(each, index); } }); return result; } public

PartitionMutableBag partitionWith(final Predicate2 predicate, final P parameter) { final PartitionMutableBag result = new PartitionHashBag(); this.forEachWithOccurrences(new ObjectIntProcedure() { public void value(T each, int index) { MutableBag bucket = predicate.accept(each, parameter) ? result.getSelected() : result.getRejected(); bucket.addOccurrences(each, index); } }); return result; } public MutableBag selectInstancesOf(final Class clazz) { final MutableBag result = HashBag.newBag(); this.forEachWithOccurrences(new ObjectIntProcedure() { public void value(T each, int occurrences) { if (clazz.isInstance(each)) { result.addOccurrences((S) each, occurrences); } } }); return result; } public MutableBooleanBag collectBoolean(BooleanFunction booleanFunction) { return this.collectBoolean(booleanFunction, new BooleanHashBag()); } public MutableByteBag collectByte(ByteFunction byteFunction) { return this.collectByte(byteFunction, new ByteHashBag()); } public MutableCharBag collectChar(CharFunction charFunction) { return this.collectChar(charFunction, new CharHashBag()); } public MutableDoubleBag collectDouble(DoubleFunction doubleFunction) { return this.collectDouble(doubleFunction, new DoubleHashBag()); } public T getFirst() { return this.items.keysView().getFirst(); } public HashBagMultimap groupBy(Function function) { return this.groupBy(function, HashBagMultimap.newMultimap()); } public MutableMap groupByUniqueKey(Function function) { throw new UnsupportedOperationException(this.getClass().getSimpleName() + ".groupByUniqueKey() not implemented yet"); } public MutableSet> zipWithIndex() { return this.zipWithIndex(UnifiedSet.>newSet()); } public T getLast() { return this.items.keysView().getLast(); } @Override public > R select(final Predicate predicate, final R target) { this.forEachWithOccurrences(new ObjectIntProcedure() { public void value(T each, int occurrences) { if (predicate.accept(each)) { for (int i = 0; i < occurrences; i++) { target.add(each); } } } }); return target; } @Override public > R selectWith( final Predicate2 predicate, final P parameter, final R target) { this.forEachWithOccurrences(new ObjectIntProcedure() { public void value(T each, int occurrences) { if (predicate.accept(each, parameter)) { for (int i = 0; i < occurrences; i++) { target.add(each); } } } }); return target; } @Override public > R reject(final Predicate predicate, final R target) { this.forEachWithOccurrences(new ObjectIntProcedure() { public void value(T each, int occurrences) { if (!predicate.accept(each)) { for (int i = 0; i < occurrences; i++) { target.add(each); } } } }); return target; } public MutableBag reject(final Predicate predicate) { final MutableBag result = HashBag.newBag(); this.forEachWithOccurrences(new ObjectIntProcedure() { public void value(T each, int index) { if (!predicate.accept(each)) { result.addOccurrences(each, index); } } }); return result; } @Override public > R rejectWith( final Predicate2 predicate, final P parameter, final R target) { this.forEachWithOccurrences(new ObjectIntProcedure() { public void value(T each, int occurrences) { if (!predicate.accept(each, parameter)) { for (int i = 0; i < occurrences; i++) { target.add(each); } } } }); return target; } public MutableBag collect(final Function function) { final HashBag result = HashBag.newBag(this.items.size()); this.forEachWithOccurrences(new ObjectIntProcedure() { public void value(T each, int occurrences) { result.addOccurrences(function.valueOf(each), occurrences); } }); return result; } public MutableFloatBag collectFloat(FloatFunction floatFunction) { return this.collectFloat(floatFunction, new FloatHashBag()); } public MutableIntBag collectInt(IntFunction intFunction) { return this.collectInt(intFunction, new IntHashBag()); } public MutableLongBag collectLong(LongFunction longFunction) { return this.collectLong(longFunction, new LongHashBag()); } public MutableShortBag collectShort(ShortFunction shortFunction) { return this.collectShort(shortFunction, new ShortHashBag()); } public MutableBag collectIf( final Predicate predicate, final Function function) { final MutableBag result = HashBag.newBag(); this.forEachWithOccurrences(new ObjectIntProcedure() { public void value(T each, int occurrences) { if (predicate.accept(each)) { result.addOccurrences(function.valueOf(each), occurrences); } } }); return result; } public MutableBag flatCollect(final Function> function) { final MutableBag result = HashBag.newBag(); this.forEachWithOccurrences(new ObjectIntProcedure() { public void value(T each, final int occurrences) { Iterable values = function.valueOf(each); Iterate.forEach(values, new Procedure() { public void value(V each) { result.addOccurrences(each, occurrences); } }); } }); return result; } @Override public > R collect(final Function function, final R target) { this.forEachWithOccurrences(new ObjectIntProcedure() { public void value(T each, int occurrences) { V value = function.valueOf(each); for (int i = 0; i < occurrences; i++) { target.add(value); } } }); return target; } public HashBagMultimap groupByEach(Function> function) { return this.groupByEach(function, HashBagMultimap.newMultimap()); } public MutableBag> zip(Iterable that) { return this.zip(that, HashBag.>newBag()); } @Override public > R collectIf( final Predicate predicate, final Function function, final R target) { this.forEachWithOccurrences(new ObjectIntProcedure() { public void value(T each, int occurrences) { if (predicate.accept(each)) { V value = function.valueOf(each); for (int i = 0; i < occurrences; i++) { target.add(value); } } } }); return target; } @Override public > R flatCollect(final Function> function, final R target) { this.forEachWithOccurrences(new ObjectIntProcedure() { public void value(T each, final int occurrences) { Iterable values = function.valueOf(each); Iterate.forEach(values, new Procedure() { public void value(V each) { for (int i = 0; i < occurrences; i++) { target.add(each); } } }); } }); return target; } @Override public T detect(Predicate predicate) { return this.items.keysView().detect(predicate); } @Override public T detectIfNone(Predicate predicate, Function0 function) { return this.items.keysView().detectIfNone(predicate, function); } @Override public int count(final Predicate predicate) { final Counter result = new Counter(); this.forEachWithOccurrences(new ObjectIntProcedure() { public void value(T each, int occurrences) { if (predicate.accept(each)) { result.add(occurrences); } } }); return result.getCount(); } @Override public boolean anySatisfy(Predicate predicate) { return this.items.keysView().anySatisfy(predicate); } @Override public boolean allSatisfy(Predicate predicate) { return this.items.keysView().allSatisfy(predicate); } @Override public boolean noneSatisfy(Predicate predicate) { return this.items.keysView().noneSatisfy(predicate); } @Override public MutableList toList() { return FastList.newList(this); } @Override public MutableSet toSet() { MutableSet result = UnifiedSet.newSet(this.sizeDistinct()); this.items.forEachKey(CollectionAddProcedure.on(result)); return result; } @Override public MutableBag toBag() { return HashBag.newBag(this); } @Override public T min(Comparator comparator) { return this.items.keysView().min(comparator); } @Override public T max(Comparator comparator) { return this.items.keysView().max(comparator); } @Override public T min() { return this.items.keysView().min(); } @Override public T max() { return this.items.keysView().max(); } @Override public > T minBy(Function function) { return this.items.keysView().minBy(function); } @Override public > T maxBy(Function function) { return this.items.keysView().maxBy(function); } @Override public long sumOfInt(final IntFunction function) { final long[] sum = {0L}; this.forEachWithOccurrences(new ObjectIntProcedure() { public void value(T each, int occurrences) { int intValue = function.intValueOf(each); sum[0] += (long) intValue * (long) occurrences; } }); return sum[0]; } @Override public double sumOfFloat(final FloatFunction function) { final double[] sum = {0.0}; this.forEachWithOccurrences(new ObjectIntProcedure() { public void value(T each, int occurrences) { float floatValue = function.floatValueOf(each); sum[0] += floatValue * (double) occurrences; } }); return sum[0]; } @Override public long sumOfLong(final LongFunction function) { final long[] sum = {0L}; this.forEachWithOccurrences(new ObjectIntProcedure() { public void value(T each, int occurrences) { long longValue = function.longValueOf(each); sum[0] += longValue * (long) occurrences; } }); return sum[0]; } @Override public double sumOfDouble(final DoubleFunction function) { final double[] sum = {0.0}; this.forEachWithOccurrences(new ObjectIntProcedure() { public void value(T each, int occurrences) { double doubleValue = function.doubleValueOf(each); sum[0] += doubleValue * (double) occurrences; } }); return sum[0]; } @Override public > R groupBy( Function function, R target) { this.forEach(MultimapPutProcedure.on(target, function)); return target; } @Override public > R groupByEach( Function> function, R target) { this.forEach(MultimapEachPutProcedure.on(target, function)); return target; } public HashBag with(T... elements) { this.addAll(Arrays.asList(elements)); return this; } public HashBag with(T element1, T element2) { this.add(element1); this.add(element2); return this; } @Override public boolean add(T item) { this.items.updateValue(item, 0, IntToIntFunctions.increment()); this.size++; return true; } public HashBag with(T element1, T element2, T element3) { this.add(element1); this.add(element2); this.add(element3); return this; } private class InternalIterator implements Iterator { private int position; private boolean isCurrentKeySet; private int currentKeyPosition; private int currentKeyOccurrences; private Iterator> keyValueIterator = HashBag.this.items.keyValuesView().iterator(); private ObjectIntPair currentKeyValue; public boolean hasNext() { return this.position != HashBag.this.size; } public T next() { if (!this.hasNext()) { throw new NoSuchElementException(); } this.isCurrentKeySet = true; if (this.currentKeyPosition < this.currentKeyOccurrences) { this.currentKeyPosition++; this.position++; return this.currentKeyValue.getOne(); } this.currentKeyValue = this.keyValueIterator.next(); this.currentKeyPosition = 1; this.currentKeyOccurrences = this.currentKeyValue.getTwo(); this.position++; return this.currentKeyValue.getOne(); } public void remove() { if (!this.isCurrentKeySet) { throw new IllegalStateException(); } this.isCurrentKeySet = false; this.position--; HashBag.this.remove(this.currentKeyValue.getOne()); this.keyValueIterator = HashBag.this.items.keyValuesView().iterator(); this.currentKeyOccurrences--; this.currentKeyPosition--; } } @Beta public ParallelUnsortedBag asParallel(ExecutorService executorService, int batchSize) { if (executorService == null) { throw new NullPointerException(); } if (batchSize < 1) { throw new IllegalArgumentException(); } return new HashBagParallelIterable(executorService, batchSize); } private final class HashUnsortedBagBatch extends AbstractBatch implements UnsortedBagBatch { private final int chunkStartIndex; private final int chunkEndIndex; private HashUnsortedBagBatch(int chunkStartIndex, int chunkEndIndex) { this.chunkStartIndex = chunkStartIndex; this.chunkEndIndex = chunkEndIndex; } public void forEach(Procedure procedure) { throw new UnsupportedOperationException("not implemented yet"); /* for (int i = this.chunkStartIndex; i < this.chunkEndIndex; i++) { if (ObjectIntHashMap.isNonSentinel(HashBag.this.items.keys[i])) { T each = HashBag.this.items.toNonSentinel(HashBag.this.items.keys[i]); int occurrences = HashBag.this.items.values[i]; for (int j = 0; j < occurrences; j++) { procedure.value(each); } } } */ } public void forEachWithOccurrences(ObjectIntProcedure procedure) { throw new UnsupportedOperationException("not implemented yet"); /* for (int i = this.chunkStartIndex; i < this.chunkEndIndex; i++) { if (ObjectIntHashMap.isNonSentinel(HashBag.this.items.keys[i])) { T each = HashBag.this.items.toNonSentinel(HashBag.this.items.keys[i]); int occurrences = HashBag.this.items.values[i]; procedure.value(each, occurrences); } } */ } public boolean anySatisfy(Predicate predicate) { throw new UnsupportedOperationException("not implemented yet"); } public boolean allSatisfy(Predicate predicate) { throw new UnsupportedOperationException("not implemented yet"); } public T detect(Predicate predicate) { throw new UnsupportedOperationException("not implemented yet"); } public UnsortedBagBatch select(Predicate predicate) { return new SelectUnsortedBagBatch(this, predicate); } public UnsortedBagBatch collect(Function function) { return new CollectUnsortedBagBatch(this, function); } } private final class HashBagParallelIterable extends AbstractParallelUnsortedBag> { private final ExecutorService executorService; private final int batchSize; private HashBagParallelIterable(ExecutorService executorService, int batchSize) { this.executorService = executorService; this.batchSize = batchSize; } @Override public ExecutorService getExecutorService() { return this.executorService; } @Override public LazyIterable> split() { return new HashBagParallelBatchLazyIterable(); } public void forEach(Procedure procedure) { forEach(this, procedure); } public boolean anySatisfy(Predicate predicate) { return anySatisfy(this, predicate); } public boolean allSatisfy(Predicate predicate) { return allSatisfy(this, predicate); } public void forEachWithOccurrences(final ObjectIntProcedure procedure) { LazyIterable> chunks = this.split(); LazyIterable> callables = chunks.collect(new Function, Callable>() { public Callable valueOf(final UnsortedBagBatch chunk) { return new Callable() { public Void call() { chunk.forEachWithOccurrences(procedure); return null; } }; } }); try { this.executorService.invokeAll(callables.toList(), Integer.MAX_VALUE, TimeUnit.DAYS); } catch (InterruptedException e) { Thread.currentThread().interrupt(); throw new RuntimeException(e); } } public T detect(Predicate predicate) { return detect(this, predicate); } private class HashBagParallelBatchIterator implements Iterator> { protected int chunkIndex; public boolean hasNext() { return this.chunkIndex * HashBagParallelIterable.this.batchSize < HashBag.this.items.size(); } public RootUnsortedBagBatch next() { throw new UnsupportedOperationException("not implemented yet"); /* int chunkStartIndex = this.chunkIndex * HashBagParallelIterable.this.batchSize; int chunkEndIndex = (this.chunkIndex + 1) * HashBagParallelIterable.this.batchSize; int truncatedChunkEndIndex = Math.min(chunkEndIndex, HashBag.this.items.keys.length); this.chunkIndex++; return new HashBagBatch(chunkStartIndex, truncatedChunkEndIndex); */ } public void remove() { throw new UnsupportedOperationException("cannot remove from a ParallelIterable"); } } private class HashBagParallelBatchLazyIterable extends AbstractLazyIterable> { public void forEach(Procedure> procedure) { for (RootUnsortedBagBatch chunk : this) { procedure.value(chunk); } } public

void forEachWith(Procedure2, ? super P> procedure, P parameter) { for (RootUnsortedBagBatch chunk : this) { procedure.value(chunk, parameter); } } public void forEachWithIndex(ObjectIntProcedure> objectIntProcedure) { throw new UnsupportedOperationException("not implemented yet"); } public Iterator> iterator() { return new HashBagParallelBatchIterator(); } } } }