com.davidbracewell.collection.AbstractMapCounter Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of mango Show documentation
Show all versions of mango Show documentation
A set of utilities and tools to speed up and ease programming in Java.
/*
* (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 extends T> items) {
this(backingMap);
incrementAll(items);
}
protected AbstractMapCounter(Map backingMap, Map extends T, ? extends Number> items) {
this(backingMap);
merge(items);
}
protected AbstractMapCounter(Map backingMap, Counter extends T> 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 extends T> 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 extends T, ? extends Number> other) {
Preconditions.checkNotNull(other);
for (Map.Entry extends T, ? extends Number> 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