让我们从List BinarySearch的重载开始:
public int BinarySearch(T item, IComparer<T> comparer);
众所周知,在使用BinarySearch之前,应使用适当的IComparer对列表进行排序。但是:要搜索列表,您必须提供T项。当使用一个基于这些项的属性(即使用Linq或delegates /谓词)来搜索列表中的项时,这是相当意外的。因为当我已经拥有我的T项时,我不必搜索它!
现在我在C#中实现了C ++代码,看到C ++程序员在他的代码中到处使用C ++样式二进制搜索,如下所示。首先,他制作了一个新的T项目并给了这个T项目他正在寻找的属性。然后他用它搜索列表,找到列表中具有相同属性的项目的索引。当然,C ++比较器适用于这些属性。
所以这是在List中查找项目的一种完全不同的方式。 BinarySearch创建一个虚拟 T项,并搜索一个索引,用它可以检索列表中的 real T项。从Linq的角度来看,这感觉不自然。
我的问题是:
我是否正确描述了BinarySearch背后的想法?
您是否认为可以在不使用虚拟T项目的情况下使用Linq样式搜索BinarySearch?
答案 0 :(得分:5)
Did I give a correct description of the idea behind BinarySearch?
是。
Do you think it is possible to use a Linq style search with BinarySearch without making a dummy T item first?
不是它的当前形式。您可以使用一个为您创建虚拟T的包装器,它只适用于特定的Ts,但是(使用无参数构造函数等)。
答案 1 :(得分:0)
实际上,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);
}
使用这些方法,您可以进行比较,该比较是您最初用于对集合进行排序的一个子集。
显然,当您使用原始比较器的子集时,您无法确定找到单个索引。因此,这些方法返回较低的二进制搜索范围。