/**
  * Calculates the third quartile for a list of numbers in ascending order.
  *
  * @param values the list of values.
  * @return The third quartile.
  */
 public static double calculateQ3(final List values) {
   double result = Double.NaN;
   final int count = values.size();
   if (count > 0) {
     if (count % 2 == 1) {
       if (count > 1) {
         result = Statistics.calculateMedian(values, count / 2 + 1, count - 1);
       } else {
         result = Statistics.calculateMedian(values, 0, 0);
       }
     } else {
       result = Statistics.calculateMedian(values, count / 2 + 1, count - 1);
     }
   }
   return result;
 }
  /**
   * Calculates the statistics required for a {@link BoxAndWhiskerItem}.
   *
   * <p>Any items in the list that are not instances of the <code>Number</code> class are ignored.
   * Likewise, <code>null</code> values are ignored.
   *
   * @param values A list of numbers (a <code>null</code> list is not permitted).
   * @return Box-and-whisker statistics.
   */
  public static BoxAndWhiskerItem calculateBoxAndWhiskerStatistics(final List values) {

    Collections.sort(values);

    final double mean = Statistics.calculateMean(values);
    final double median = Statistics.calculateMedian(values, false);
    final double q1 = calculateQ1(values);
    final double q3 = calculateQ3(values);

    final double interQuartileRange = q3 - q1;

    final double upperOutlierThreshold = q3 + (interQuartileRange * 1.5);
    final double lowerOutlierThreshold = q1 - (interQuartileRange * 1.5);

    final double upperFaroutThreshold = q3 + (interQuartileRange * 2.0);
    final double lowerFaroutThreshold = q1 - (interQuartileRange * 2.0);

    double minRegularValue = Double.POSITIVE_INFINITY;
    double maxRegularValue = Double.NEGATIVE_INFINITY;
    double minOutlier = Double.POSITIVE_INFINITY;
    double maxOutlier = Double.NEGATIVE_INFINITY;
    final List outliers = new ArrayList();

    final Iterator iterator = values.iterator();
    while (iterator.hasNext()) {
      final Object object = iterator.next();
      if (object != null && object instanceof Number) {
        final Number number = (Number) object;
        final double value = number.doubleValue();
        if (value > upperOutlierThreshold) {
          outliers.add(number);
          if (value > maxOutlier && value <= upperFaroutThreshold) {
            maxOutlier = value;
          }
        } else if (value < lowerOutlierThreshold) {
          outliers.add(number);
          if (value < minOutlier && value >= lowerFaroutThreshold) {
            minOutlier = value;
          }
        } else {
          if (minRegularValue == Double.NaN) {
            minRegularValue = value;
          } else {
            minRegularValue = Math.min(minRegularValue, value);
          }
          if (maxRegularValue == Double.NaN) {
            maxRegularValue = value;
          } else {
            maxRegularValue = Math.max(maxRegularValue, value);
          }
        }
      }
    }
    minOutlier = Math.min(minOutlier, minRegularValue);
    maxOutlier = Math.max(maxOutlier, maxRegularValue);

    return new BoxAndWhiskerItem(
        new Double(mean),
        new Double(median),
        new Double(q1),
        new Double(q3),
        new Double(minRegularValue),
        new Double(maxRegularValue),
        new Double(minOutlier),
        new Double(maxOutlier),
        outliers);
  }