C# 如何对列表使用BinarySearch<;T>;

C# 如何对列表使用BinarySearch<;T>;,c#,list,binary-search,C#,List,Binary Search,让我们从这个列表BinarySearch重载开始: public int BinarySearch(T item, IComparer<T> comparer); public int-BinarySearch(T项,i比较程序); 众所周知,在使用BinarySearch之前,应该使用适当的IComparer对列表进行排序。但是:要搜索列表,您必须提供一个T项。当人们习惯于根据列表中项目的属性(即使用Linq或委托/谓词)搜索这些项目时,这是非常意外的。因为当我已经有我的T项目

让我们从这个列表BinarySearch重载开始:

public int BinarySearch(T item, IComparer<T> comparer);
public int-BinarySearch(T项,i比较程序);
众所周知,在使用BinarySearch之前,应该使用适当的IComparer对列表进行排序。但是:要搜索列表,您必须提供一个T项。当人们习惯于根据列表中项目的属性(即使用Linq或委托/谓词)搜索这些项目时,这是非常意外的。因为当我已经有我的T项目,我不必搜索它

<>我现在在C++中实现C++代码,看到C++程序员在代码中到处使用C++风格的二进制搜索如下。首先,他制作了一个新的T项目,并给了这个T项目他正在寻找的属性。然后他用它搜索列表,以找到列表中具有相同属性的项的索引。当然,C++的比较器适合这些性质。 因此,这是一种在列表中查找项目的完全不同的方法。BinarySearch生成一个伪T项,并搜索一个索引,通过该索引可以检索列表中的真实T项。从Linq的角度来看,这感觉很不自然

我的问题是:

我是否正确描述了BinarySearch背后的思想


您是否认为可以使用Linq样式的搜索和BinarySearch,而不首先生成一个伪T项?

我是否正确描述了BinarySearch背后的思想?

您认为可以在不首先生成伪T项的情况下,将Linq样式的搜索与BinarySearch结合使用吗?


不是以现在的形式。您可以使用一个包装器为您创建虚拟T,它只适用于特定的T(使用无参数构造函数等)。

实际上,LINQ中没有类似的东西,但是您可以构建自己的扩展。 此示例允许您传递的不是虚拟项,而是原始比较器中使用的属性:

public static int FindFirstIndexGreaterThanOrEqualTo<TElement, TKey>(
                this IList<TElement> keySortedCollection,
                TKey key,
                Func<TElement, TKey> keySelector,
                IComparer<TKey> keyComparer)
{
    int begin = 0;
    int end = keySortedCollection.Count;
    while (end > begin)
    {
        int index = (begin + end) / 2;
        TElement el = keySortedCollection[index];
        TKey currElKey = keySelector(el);
        if (keyComparer.Compare(currElKey, key) >= 0)
            end = index;
        else
            begin = index + 1;
    }
    return end;
}

public static int FindFirstIndexGreaterThanOrEqualTo<TElement, TKey>(
                this IList<TElement> keySortedCollection,
                TKey key,
                Func<TElement, TKey> keySelector)
{
    return FindFirstIndexGreaterThanOrEqualTo(keySortedCollection,
                                               key,
                                               keySelector,
                                               Comparer<TKey>.Default);
}
公共静态int-findFirstIndex大于或等于(
此IList keySortedCollection,
TKey键,
Func键选择器,
i比较键(比较器)
{
int begin=0;
int end=keySortedCollection.Count;
while(结束>开始)
{
int索引=(开始+结束)/2;
TElement el=keySortedCollection[索引];
TKey currElKey=按键选择器(el);
if(keycomarer.Compare(currElKey,key)>=0)
结束=索引;
其他的
开始=索引+1;
}
返回端;
}
公共静态int FindFirstIndex大于或等于(
此IList keySortedCollection,
TKey键,
Func键选择器)
{
返回FindFirstIndex大于或等于(keySortedCollection,
钥匙
按键选择器,
比较器(默认值);
}
使用这些方法,您可以提供一个比较,该比较是最初用于对集合进行排序的比较的子集


显然,当您使用原始比较器的子集时,您不能确保找到单个索引。因此,这些方法返回二进制搜索的下限。

添加了一些解释。(否则,这似乎是离题的…)为什么这只适用于特定的T,任何关于它的文档?你不能(实际上)对所有实体都有一个通用的创建方法。您的类具有不同数量的构造函数参数-您会自动选择哪一个?如何自动提供参数?对于可以限制的结构和无参数类来说,这很容易。在这方面,简单地创建一个伪T(IMHO)是一种更容易的方法,因为T可以是任何东西。也许使用通用语法“where T:Basetype”和包装器可以使用Basetype的构造函数会有所帮助?并且像这样限制通用参数只允许特定的T(如我前面所述)-仅限
Basetype
的后代。关键是,您必须为您想要使用的每个
BaseType
创建T in代码。