org.apache.jackrabbit.commons.flat.Rank Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of aem-sdk-api Show documentation
Show all versions of aem-sdk-api Show documentation
The Adobe Experience Manager SDK
/*
* 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.jackrabbit.commons.flat;
import java.lang.reflect.Array;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.NoSuchElementException;
/**
*
* This class does efficient ranking of values of type T
wrt. to a
* {@link Comparator} for T
. After creating an instance of
* Rank
, the {@link #take(int)} method returns the next
* k
smallest values. That is, each of these values is smaller than
* every value not yet retrieved. The order of the values returned by
* take
is not specified in general. However if the values are in
* increasing order, the values returned by take
will also be in
* increasing order.
*
*
* Note: The values may not contain duplicates or the behavior
* of take
is not defined.
*
*
* @param Type of values in this Rank
.
*/
public class Rank {
private final T[] values;
private final Comparator super T> order;
private int first;
/**
* Create a new instance of Rank
for a given array of
* values
and a given order
. The
* values
are manipulated in place, no copying is performed.
*
* @param values values for ranking. Duplicates are not allowed.
* @param order Ordering for ranking
*/
public Rank(T[] values, Comparator super T> order) {
super();
this.values = values;
this.order = order;
}
/**
* Create a new instance of Rank
for a given collection of
* values
and a given order
. The
* values
are copied into an internal array before they are
* manipulated.
*
* @param values values for ranking. Duplicates are not allowed.
* @param componentType type evidence for the values
* @param order Ordering for ranking
*/
public Rank(Collection values, Class componentType, Comparator super T> order) {
super();
this.values = toArray(values, componentType);
this.order = order;
}
/**
* Create a new instance of Rank
for the first
* count
values in a a given iterator of values
* and a given order
. The values
are copied into
* an internal array before they are manipulated.
*
* @param values values for ranking. Duplicates are not allowed.
* @param componentType type evidence for the values
* @param count Number of items to include. -1 for all.
* @param order Ordering for ranking
*/
public Rank(Iterator values, Class componentType, int count, Comparator super T> order) {
super();
this.order = order;
if (count >= 0) {
this.values = createArray(count, componentType);
for (int k = 0; k < count; k++) {
this.values[k] = values.next();
}
}
else {
List l = new LinkedList();
while (values.hasNext()) {
l.add(values.next());
}
this.values = toArray(l, componentType);
}
}
/**
* Create a new instance of Rank
for a given array of
* values
. The order is determined by the natural ordering of
* the values (i.e. through {@link Comparable}). The values
are
* manipulated in place, no copying is performed.
*
* @param extends Comparable<S>
* @param values values for ranking. Duplicates are not allowed.
* @return A new instance of Rank
.
*/
public static > Rank rank(S[] values) {
return new Rank(values, Rank.comparableComparator());
}
/**
* Create a new instance of Rank
for a given collection of
* values
. The order is determined by the natural ordering of
* the values (i.e. through {@link Comparable}). The values
are
* copied into an internal array before they are manipulated.
*
* @param extends Comparable<S>
* @param values values for ranking. Duplicates are not allowed.
* @param componentType type evidence for the values
* @return A new instance of Rank
.
*/
public static > Rank rank(Collection values, Class componentType) {
return new Rank(values, componentType, Rank.comparableComparator());
}
/**
* Create a new instance of Rank
for the first
* count
values in a a given iterator of values
.
* The order is determined by the natural ordering of the values (i.e.
* through {@link Comparable}). The values
are copied into an
* internal array before they are manipulated.
*
* @param extends Comparable<S>
* @param values values for ranking. Duplicates are not allowed.
* @param componentType type evidence for the values
* @param count Number of items to include. -1 for all.
* @return A new instance of Rank
.
*/
public static > Rank rank(Iterator values, Class componentType, int count) {
return new Rank(values, componentType, count, Rank.comparableComparator());
}
/**
* Utility method for creating a {@link Comparator} of T
from a
* {@link Comparable} of type T
.
*
* @param extends Comparable<T>
* @return Comparator whose order is defined by T
.
*/
public static > Comparator comparableComparator() {
return new Comparator() {
public int compare(T c1, T c2) {
return c1.compareTo(c2);
}
};
}
public Comparator super T> getOrder() {
return order;
}
/**
* Returns the n
-th smallest values remaining in this
* Rank
.
*
* @param n Number of values to return
* @return An iterator containing the next n
smallest values.
* @throws NoSuchElementException if this Rank
has not enough
* remaining elements or when n
is negative.
*/
public Iterator take(int n) {
if (n < 0 || n + first > values.length) {
throw new NoSuchElementException();
}
if (n > 0) {
take(n, first, values.length - 1);
first += n;
return Arrays.asList(values).subList(first - n, first).iterator();
} else {
return Collections.emptySet().iterator();
}
}
/**
* Returns the number of remaining items in the Rank
.
*
* @return number of remaining items.
*/
public int size() {
return values.length - first;
}
// -----------------------------------------------------< internal >---
/**
* Rearrange {@link #values} such that each of the n
first
* values starting at from
is smaller that all the remaining
* items up to to
.
*/
private void take(int n, int from, int to) {
// Shortcut for all values
if (n >= to - from + 1) {
return;
}
// Choosing the n-th value as pivot results in correct partitioning after one pass
// for already ordered values.
int pivot = from + n - 1;
int lo = from;
int hi = to;
// Partition values around pivot
while (lo < hi) {
// Find values to swap around the pivot
while (order.compare(values[lo], values[pivot]) < 0) {
lo++;
}
while (order.compare(values[hi], values[pivot]) > 0) {
hi--;
}
if (lo < hi) {
// Swap values and keep track of pivot position in case the pivot itself is swapped
if (lo == pivot) {
pivot = hi;
} else if (hi == pivot) {
pivot = lo;
}
swap(lo, hi);
lo++;
hi--;
}
}
// Actual number of values taken
int nn = pivot + 1 - from;
if (nn > n) { // Recurse: take first n elements from first partition
take(n, from, pivot);
}
else if (nn < n) { // Recurse: take first n - nn elements from second partition
take(n - nn, pivot + 1, to);
}
// else done
}
private void swap(int lo, int hi) {
T t1 = values[lo];
T t2 = values[hi];
if (order.compare(t1, t2) == 0) {
throw new IllegalStateException("Detected duplicates " + t1);
}
values[lo] = t2;
values[hi] = t1;
}
// -----------------------------------------------------< utility >---
private static S[] toArray(Collection collection, Class componentType) {
return collection.toArray(createArray(collection.size(), componentType));
}
@SuppressWarnings("unchecked")
private static S[] createArray(int size, Class componentType) {
return (S[]) Array.newInstance(componentType, size);
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy