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

org.apache.solr.analytics.util.MedianCalculator Maven / Gradle / Ivy

There is a newer version: 9.7.0
Show newest version
/*
 * 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 org.apache.solr.analytics.util;

import java.util.List;

public class MedianCalculator {

  /**
   * Calculates the median of the given list of numbers.
   *
   * @param list A list of {@link Comparable} {@link Number} objects
   * @return The median of the given list as a double.
   */
  public static > double getMedian(List list) {
    int size = list.size() - 1;
    if (size == -1) {
      return 0;
    }

    select(list, .5 * size, 0, size);

    int firstIdx = (int) (Math.floor(.5 * size));
    int secondIdx = (firstIdx <= size && size % 2 == 1) ? firstIdx + 1 : firstIdx;
    double result = list.get(firstIdx).doubleValue() * .5 + list.get(secondIdx).doubleValue() * .5;

    return result;
  }

  private static > void select(List list, double place, int begin, int end) {
    T split;
    if (end - begin < 10) {
      split = list.get((int) (Math.random() * (end - begin + 1)) + begin);
    } else {
      split = split(list, begin, end);
    }

    Point result = partition(list, begin, end, split);

    if (place < result.low) {
      select(list, place, begin, result.low);
    } else if (place > result.high) {
      select(list, place, result.high, end);
    } else {
      if (result.low == (int) (Math.floor(place)) && result.low > begin) {
        select(list, result.low, begin, result.low);
      }
      if (result.high == (int) (Math.ceil(place)) && result.high < end) {
        select(list, result.high, result.high, end);
      }
    }
  }

  private static > T split(List list, int begin, int end) {
    T temp;
    int num = (end - begin + 1);
    int recursiveSize = (int) Math.sqrt((double) num);
    int step = num / recursiveSize;
    for (int i = 1; i < recursiveSize; i++) {
      int swapFrom = i * step + begin;
      int swapTo = i + begin;
      temp = list.get(swapFrom);
      list.set(swapFrom, list.get(swapTo));
      list.set(swapTo, temp);
    }
    recursiveSize--;
    select(list, recursiveSize / 2 + begin, begin, recursiveSize + begin);
    return list.get(recursiveSize / 2 + begin);
  }

  private static > Point partition(List list, int begin, int end, T indexElement) {
    T temp;
    int left, right;
    for (left = begin, right = end; left < right; left++, right--) {
      while (list.get(left).compareTo(indexElement) < 0) {
        left++;
      }
      while (right != begin - 1 && list.get(right).compareTo(indexElement) >= 0) {
        right--;
      }
      if (right <= left) {
        left--;
        right++;
        break;
      }
      temp = list.get(left);
      list.set(left, list.get(right));
      list.set(right, temp);
    }
    while (left != begin - 1 && list.get(left).compareTo(indexElement) >= 0) {
      left--;
    }
    while (right != end + 1 && list.get(right).compareTo(indexElement) <= 0) {
      right++;
    }
    int rightMove = right + 1;
    while (rightMove < end + 1) {
      if (list.get(rightMove).equals(indexElement)) {
        temp = list.get(rightMove);
        list.set(rightMove, list.get(right));
        list.set(right, temp);
        do {
          right++;
        } while (list.get(right).equals(indexElement));
        if (rightMove <= right) {
          rightMove = right;
        }
      }
      rightMove++;
    }
    return new Point(left, right);
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy