简体   繁体   English

SortedList 上是否有下界函数<K ,V> ?

[英]Is there a Lower Bound function on a SortedList<K ,V>?

Is there a Lower Bound function on a SortedList<K ,V> ? SortedList<K ,V>上是否有下界函数? The function should return the first element equal to or greater than the specified key.该函数应返回等于或大于指定键的第一个元素。 Is there some other class that supports this?有没有其他类支持这个?

Guys - please read the question once again.伙计们 - 请再次阅读这个问题。 I do not need a function that returns the key if it is present.如果键存在,我不需要返回键的函数。 I'm interested in scenario when there is no exact key matching.我对没有精确键匹配的场景感兴趣。

I'm interested in O(log n) time .我对 O(log n) 时间感兴趣 It means that I do not have a problem with foreach loop, but rather would like to have an efficient way of doing this.这意味着我对 foreach 循环没有问题,而是希望有一种有效的方法来做到这一点。

I have done some tests on this.我对此做了一些测试。

Linq statements are not optimized by neither the compiler nor runtime machine, so they walk through all collection elements and are slow O(n). Linq 语句既没有被编译器也没有被运行时机器优化,所以它们遍历所有集合元素并且慢 O(n)。 Based on Mehrdad Afshari answer, here is a Binary Search that works in O(log n) on the Keys collection:根据 Mehrdad Afshari 的回答,这里是一个二进制搜索,它在 Keys 集合上以 O(log n) 运行:

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;
}

Binary search the SortedList.Keys collection.SortedList.Keys集合进行二分搜索。

Here we go.开始了。 This is O(log n ):这是 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);
}

I'd go with LINQ (presuming you're using C#3), but using the overload of FirstOrDefault that takes a predicate:我会使用 LINQ(假设您使用的是 C#3),但是使用带有谓词的 FirstOrDefault 的重载:

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

(a lot of the other Enumerable methods can also take predicates which is a nice shortcut) (许多其他 Enumerable 方法也可以使用谓词,这是一个很好的捷径)

Not aware of one, but it's a simple LINQ statement:不知道,但这是一个简单的 LINQ 语句:

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

first will either be the first object that passes the comparison or default(T) (which is normally null ). first要么是通过比较的第一个对象,要么是default(T) (通常为null )。

Edit编辑

DaveW's version: DaveW 的版本:

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

does the same job but could potentially be faster, you'd have to test it though.做同样的工作,但可能会更快,但你必须测试它。

Or you can write own extension method to do this.或者您可以编写自己的扩展方法来执行此操作。 Note that all those functions are NOT guaranteed to go in a sequesce.请注意,不能保证所有这些功能都会按顺序进行。

Is there a Lower Bound function on a SortedList<K ,V>? SortedList<K ,V> 上有下界函数吗? The function should return the first element equal to or greater than the specified key.该函数应返回等于或大于指定键的第一个元素。

This example is implemented as an extension to SortedList and it returns the value of the smallest element greater than or equal to provided key.此示例是作为 SortedList 的扩展实现的,它返回大于或等于提供的键的最小元素的值。 It returns default(TValue) in case all keys are smaller than provided key or if an empty list was provided如果所有键都小于提供的键或提供了空列表,则返回 default(TValue)

public static TValue LowerBound<TKey, TValue>(this SortedList<TKey, TValue> list, TKey key) {
  if (list.Count == 0)
    return default;

  var comparer = list.Comparer;
  if (comparer.Compare(list.Keys[list.Keys.Count - 1], key) < 0)
    return default; // if all elements are smaller, then no lower bound

  int first = 0, last = list.Count - 1;
  while (first < last) {
    var middle = first + (last - first) / 2;
    if (comparer.Compare(list.Keys[middle], key) >= 0)
      last = middle;
    else
      first = middle + 1;
  }
  return list[list.Keys[last]];
}

Usage example:用法示例:

SortedList<string, Object> myList = new SortedList<string, Object>();
...
var value = myList.LowerBound<string, Object>("theKey");

Hopefully this should be faster, depending on SortedList's implementation.希望这应该更快,这取决于 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;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM