@Override
 public AggregateResult doMeasureUser(TestUser user, MeanAccumulator context) {
   List<ScoredId> recommendations = user.getRecommendations(30, candidates, exclude);
   if (recommendations == null || recommendations.isEmpty()) {
     context1.add(0.0);
     context5.add(0.0);
     context10.add(0.0);
     context15.add(0.0);
     context20.add(0.0);
     context25.add(0.0);
     context30.add(0.0);
     return null;
   }
   double ndcg1 = measureUser(user, context1, recommendations, 1);
   double ndcg5 = measureUser(user, context5, recommendations, 5);
   double ndcg10 = measureUser(user, context10, recommendations, 10);
   double ndcg15 = measureUser(user, context15, recommendations, 15);
   double ndcg20 = measureUser(user, context20, recommendations, 20);
   double ndcg25 = measureUser(user, context25, recommendations, 25);
   double ndcg30 = measureUser(user, context30, recommendations, 30);
   return new AggregateResult(ndcg1, ndcg5, ndcg10, ndcg15, ndcg20, ndcg25, ndcg30);
 }
  public double measureUser(
      TestUser user, MeanAccumulator context, List<ScoredId> recommendations, int listSize) {
    if (recommendations.size() > listSize) {
      recommendations = new ArrayList<ScoredId>(recommendations.subList(0, listSize));
    }
    SparseVector ratings = user.getTestRatings();
    LongList ideal = ratings.keysByValue(true);
    if (ideal.size() > listSize) {
      ideal = ideal.subList(0, listSize);
    }
    double idealGain = computeDCG(ideal, ratings);

    LongList actual = new LongArrayList(recommendations.size());
    for (ScoredId id : recommendations) {
      actual.add(id.getId());
    }
    double gain = computeDCG(actual, ratings);

    double score = gain / idealGain;

    context.add(score);
    return score;
  }