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

com.davidbracewell.collection.AbstractMapCounter Maven / Gradle / Ivy

There is a newer version: 0.5
Show newest version
/*
 * (c) 2005 David B. Bracewell
 *
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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.davidbracewell.collection;

import com.davidbracewell.conversion.Cast;
import com.google.common.base.Preconditions;
import com.google.common.collect.ForwardingIterator;
import com.google.common.collect.ForwardingSet;
import com.google.common.primitives.Doubles;
import com.google.common.util.concurrent.AtomicDouble;
import lombok.EqualsAndHashCode;
import lombok.NonNull;

import java.io.Serializable;
import java.util.*;
import java.util.function.DoublePredicate;
import java.util.function.DoubleUnaryOperator;
import java.util.function.Function;
import java.util.function.Predicate;

/**
 * 

Abstract class for counters backed by java.util.Map implementations.

* * @author David B. Bracewell */ @EqualsAndHashCode(exclude = {"sum"}) abstract class AbstractMapCounter implements Counter, Serializable { private static final long serialVersionUID = 1L; private final Map map; private AtomicDouble sum = new AtomicDouble(0d); protected AbstractMapCounter(Map backingMap) { this.map = backingMap; this.sum.set(0d); } protected AbstractMapCounter(Map backingMap, Iterable items) { this(backingMap); incrementAll(items); } protected AbstractMapCounter(Map backingMap, Map items) { this(backingMap); merge(items); } protected AbstractMapCounter(Map backingMap, Counter items) { this(backingMap); merge(items); } @Override public double get(T item) { Double returnValue = map.get(item); return returnValue == null ? 0.0d : returnValue; } @Override public void increment(T item, double amount) { if (amount == 0) { return; } double total = get(item) + amount; if (total == 0) { map.remove(item); } else { map.put(item, total); } sum.addAndGet(amount); } @Override public Map asMap() { return Collections.unmodifiableMap(map); } @Override public boolean isEmpty() { return map.isEmpty(); } @Override public int size() { return map.size(); } @Override public Set items() { return Collections.unmodifiableSet(map.keySet()); } @Override public Collection counts() { return Collections.unmodifiableCollection(map.values()); } @Override public Counter merge(Counter other) { merge(Preconditions.checkNotNull(other).asMap()); return this; } @Override public void removeZeroCounts() { for (Iterator> entryItr = map.entrySet().iterator(); entryItr.hasNext(); ) { Map.Entry entry = entryItr.next(); if (entry.getValue() == 0.0d) { entryItr.remove(); } } } @Override public void merge(Map other) { Preconditions.checkNotNull(other); for (Map.Entry entry : other.entrySet()) { increment(entry.getKey(), entry.getValue().doubleValue()); } } @Override public boolean contains(T item) { return map.containsKey(item); } @Override public String toString() { return map.toString(); } @Override public void clear() { map.clear(); sum.set(0d); } @Override public double remove(T item) { Preconditions.checkNotNull(item); double value = get(item); map.remove(item); sum.addAndGet(-value); return value; } @Override public void set(T item, double count) { remove(item); increment(item, count); } @Override public void divideBySum() { if (map.isEmpty()) { return; } for (T key : map.keySet()) { map.put(key, map.get(key) / sum()); } sum.set(1d); } @Override public Set> entries() { return new ForwardingSet>() { @Override protected Set> delegate() { return map.entrySet(); } @Override public boolean remove(Object object) { if (super.remove(object)) { sum.addAndGet(-Cast.>as(object).getValue()); return true; } return false; } @Override public boolean removeAll(Collection collection) { return standardRemoveAll(collection); } @Override public Iterator> iterator() { return new ForwardingIterator>() { final Iterator> iterator = map.entrySet().iterator(); Map.Entry entry; @Override protected Iterator> delegate() { return iterator; } @Override public Map.Entry next() { entry = super.next(); return entry; } @Override public void remove() { super.remove(); sum.addAndGet(-entry.getValue()); } }; } }; } @Override public void removeAll(Iterable items) { if (items != null) { items.forEach(this::remove); } } @Override public Counter adjustValues(@NonNull DoubleUnaryOperator function) { Counter newCounter = newInstance(); for (Map.Entry entry : map.entrySet()) { double value = function.applyAsDouble(entry.getValue()); if (value != 0d && Doubles.isFinite(value)) { newCounter.set(entry.getKey(), value); } } return newCounter; } @Override public void adjustValuesSelf(@NonNull DoubleUnaryOperator function) { map.entrySet().forEach(entry -> entry.setValue(function.applyAsDouble(entry.getValue()))); sum.set(Collect.sum(map.values())); } protected abstract Counter newInstance(); @Override public Counter topN(int n) { Counter cprime = newInstance(); itemsByCount(false).stream() .limit(n) .forEach(t -> cprime.set(t, get(t))); return cprime; } @Override public Counter bottomN(int n) { Counter cprime = newInstance(); itemsByCount(true).stream() .limit(n) .forEach(t -> cprime.set(t, get(t))); return cprime; } @Override public Counter filterByValue(@NonNull DoublePredicate doublePredicate) { Counter counter = newInstance(); map.entrySet().stream() .filter(e -> doublePredicate.test(e.getValue())) .forEach(e -> counter.set(e.getKey(), e.getValue())); return counter; } @Override public Counter filterByKey(@NonNull Predicate predicate) { Counter counter = newInstance(); map.entrySet().stream() .filter(e -> predicate.test(e.getKey())) .forEach(e -> counter.set(e.getKey(), e.getValue())); return counter; } @Override public double sum() { return sum.get(); } @Override public Counter mapKeys(@NonNull Function function) { Counter result = newInstance(); map.forEach((k, v) -> result.increment(function.apply(k), v)); return result; } }//END OF AbstractMapCounter




© 2015 - 2025 Weber Informatics LLC | Privacy Policy