Есть ли функция Lower Bound на SortedList <K, V>?

Есть ли более низкая функция на SortedList<K ,V>? Функция должна возвращать первый элемент, равный или превышающий указанный ключ. Есть ли другой класс, который поддерживает это?

Ребята - пожалуйста, снова прочитайте вопрос. Мне не нужна функция, которая возвращает ключ, если он присутствует. Мне интересен сценарий, когда нет точного соответствия клавиш.

Меня интересует время O (log n). Это означает, что у меня нет проблем с циклом foreach, но хотелось бы иметь эффективный способ сделать это.

Я сделал несколько тестов на этом.

Операторы Linq не оптимизируются ни компилятором, ни машиной времени исполнения, поэтому они проходят через все элементы коллекции и медленны O (n). На основании ответа Мехрдада Афшари, вот двоичный поиск, который работает в O (log n) в коллекции Keys:

public static int FindFirstIndexGreaterThanOrEqualTo<T>(
            this IList<T> sortedCollection, T key
        ) where T : IComparable<T> {
    int begin = 0;
    int end = sortedCollection.Count;
    while (end > begin) {
        int index = (begin + end) / 2;
        T el = sortedCollection[index];
        if (el.CompareTo(key) >= 0)
            end = index;
        else
            begin = index + 1;
    }
    return end;
}

Ответ 1

Двоичный поиск коллекции SortedList.Keys.

Здесь мы идем. Это O (log n):

private static int BinarySearch<T>(IList<T> list, T value)
{
    if (list == null)
        throw new ArgumentNullException("list");
    var comp = Comparer<T>.Default;
    int lo = 0, hi = list.Count - 1;
    while (lo < hi) {
            int m = (hi + lo) / 2;  // this might overflow; be careful.
            if (comp.Compare(list[m], value) < 0) lo = m + 1;
            else hi = m - 1;
    }
    if (comp.Compare(list[lo], value) < 0) lo++;
    return lo;
}

public static int FindFirstIndexGreaterThanOrEqualTo<T,U>
                          (this SortedList<T,U> sortedList, T key)
{
    return BinarySearch(sortedList.Keys, key);
}

Ответ 2

Не известно об одном, но это простой оператор LINQ:

first = sortedList.Where(x => x >= theObjectForComparison).FirstOrDefault();

first будет либо первым объектом, который проходит сравнение, либо default(T) (обычно это null).

Edit

Версия DaveW:

first = sortedList.FirstOrDefault(x => x >= theObjectForComparison);

выполняет ту же работу, но потенциально может быть быстрее, вам придется ее протестировать.

Ответ 3

Я бы пошел с LINQ (предположим, что вы используете С# 3), но используя перегрузку FirstOrDefault, которая берет предикат:

first = sortedList.FirstOrDefault(x => x >= theObjectForComparison);

(многие другие методы Enumerable также могут принимать предикаты, которые являются хорошим ярлыком)

Ответ 4

Или вы можете написать собственный метод расширения для этого. Обратите внимание, что все эти функции НЕ гарантированно идут в секвестре.

Ответ 5

Надеюсь, это должно быть быстрее, в зависимости от реализации SortedList.

public static int FindFirstIndexGreaterThanOrEqualTo<K, V>(
        this SortedList<K, V> sortedCollection, K key
    ) where V : new()
{
    if (sortedCollection.ContainsKey(key))
    {
        return sortedCollection.IndexOfKey(key);
    }
    sortedCollection[key] = new V();
    int retval = sortedCollection.IndexOfKey(key);
    sortedCollection.Remove(key);
    return retval;
}