/**
* Copyright (c) 2010, 2013 Darmstadt University of Technology.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Marcel Bruch - initial API and implementation.
*/
package org.eclipse.recommenders.utils;
import static org.eclipse.recommenders.utils.Checks.ensureIsInRange;
import java.util.Comparator;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import org.eclipse.recommenders.utils.names.IMethodName;
import com.google.common.annotations.Beta;
import com.google.common.base.Predicate;
import com.google.common.collect.Iterables;
import com.google.common.collect.Ordering;
@Beta
public final class Recommendations {
private Recommendations() {
// Not meant to be instantiated
}
private static final Comparator<Recommendation<?>> C_BY_RELEVANCE = new Comparator<Recommendation<?>>() {
@Override
public int compare(final Recommendation<?> lhs, final Recommendation<?> rhs) {
int compareRelevance = Double.compare(lhs.getRelevance(), rhs.getRelevance());
if (compareRelevance != 0) {
return compareRelevance;
}
return lhs.getProposal().toString().compareTo(rhs.getProposal().toString());
}
};
private static final Comparator<Recommendation<?>> C_BY_NAME = new Comparator<Recommendation<?>>() {
@Override
public int compare(final Recommendation<?> lhs, final Recommendation<?> rhs) {
return lhs.getProposal().toString().compareTo(rhs.getProposal().toString());
}
};
private static final Predicate<Recommendation<IMethodName>> P_VOID = new Predicate<Recommendation<IMethodName>>() {
@Override
public boolean apply(final Recommendation<IMethodName> input) {
if (input != null) {
return !input.getProposal().isVoid();
} else {
return false;
}
}
};
private static Predicate<Recommendation<?>> newMinimumRelevancePredicate(final double min) {
return new Predicate<Recommendation<?>>() {
@Override
public boolean apply(final Recommendation<?> input) {
if (input != null) {
return input.getRelevance() >= min;
} else {
return false;
}
}
};
}
/**
* Returns the top k elements of the given list of recommendations, sorted by proposal relevance in descending
* order.
*/
public static <R extends Recommendation<T>, T> List<R> top(final Iterable<R> recommendations,
final int numberOfTopElements) {
return Ordering.from(C_BY_RELEVANCE).greatestOf(recommendations, numberOfTopElements);
}
/**
* Returns the top k elements of the given list of recommendations that satisfy the minimum relevance criterion,
* sorted by proposal relevance in descending order.
*/
public static <R extends Recommendation<T>, T> List<R> top(final Iterable<R> recommendations,
final int numberOfTopElements, final double minRelevance) {
return Ordering.from(C_BY_RELEVANCE).greatestOf(filterRelevance(recommendations, minRelevance),
numberOfTopElements);
}
/**
* Filters all void methods from the list of method recommendations.
*/
public static Iterable<Recommendation<IMethodName>> filterVoid(
final Iterable<Recommendation<IMethodName>> recommendations) {
return Iterables.filter(recommendations, P_VOID);
};
/**
* Filters all proposals whose relevance is below the given threshold.
*/
public static <R extends Recommendation<T>, T> Iterable<R> filterRelevance(final Iterable<R> recommendations,
final double min) {
return Iterables.filter(recommendations, newMinimumRelevancePredicate(min));
};
/**
* Sorts the given list of proposals lexicographically in ascending order by the outcome of the proposal's toString
* output.
*/
public static <R extends Recommendation<T>, T> List<R> sortByName(final Iterable<R> recommendations) {
return Ordering.from(C_BY_NAME).sortedCopy(recommendations);
}
/**
* Sorts the given list of proposals in ascending order by the recommendation's relevance.
*/
public static <R extends Recommendation<T>, T> List<R> sortByRelevance(final Iterable<R> recommendations) {
return Ordering.from(C_BY_RELEVANCE).reverse().sortedCopy(recommendations);
}
/**
* Returns the relevance of the give proposal multiplied by 100 and rounded to the next Integer. Note that this
* method checks that the relevance is in the range of [0, 1].
*/
public static int asPercentage(Recommendation<?> recommendation) {
double rel = recommendation.getRelevance();
ensureIsInRange(rel, 0, 1, "relevance '%f' not in interval [0, 1]", rel);
return (int) Math.round(rel * 100);
}
/**
* Returns all proposals of the given iterable of recommendations.
*
* @see Recommendation#getProposal()
*/
public static <R extends Recommendation<T>, T> List<T> getProposals(final Iterable<R> recommendations) {
List<T> res = new LinkedList<>();
for (Recommendation<T> rec : recommendations) {
res.add(rec.getProposal());
}
return res;
}
/**
* Returns the given recommendations as map.
*/
public static <R extends Recommendation<T>, T> Map<T, Double> asMap(final Iterable<R> recommendations) {
Map<T, Double> res = new HashMap<>();
for (Recommendation<T> rec : recommendations) {
res.put(rec.getProposal(), rec.getRelevance());
}
return res;
}
}