采用委托条件的二进制搜索一个C#列表 [英] Binary search of a C# list using delegate condition
问题描述
我有一个列表< T>
我要搜索不是一个给定的项目,但为了满足给定条件的项目。鉴于该列表中的项目我可以测试的4个条件是正确的:
- 所需的项目必须是左
- 所需的项目必须是在正确的
- ,这是需要的项目
- 所需不能在列表
在列表功能快速浏览不鼓励,所以我想知道如果任何人知道了一个功能,我可以使用<? / p>
编辑:这是一个本地临时表,所以我知道它会被正确地排序
编辑:BinarySearch的长相差不多吧,但在我来说,我没有与比较的项目。我会用乔恩斯基特的解决方案,而忽略1阿根廷,但我不知道,我可以在它总是被同一个ARG计数。
新编辑:我会留下多余的二进制搜索下方,因为他们会成为有用的人,这里的是我觉得你真正想要的最终选择。您的代理应该返回一个正数,如果它要寻找的项目是小于指定的,如果是大于一指定,0,如果它只是对的。
负数
公共静态INT BinarySearchForMatch< T>(这个IList的< T>列表中,
Func键< T,INT>比较器)
{
INT分钟= 0;
INT最大= list.Count-1;
,而(分钟< =最大值)
{
INT中旬=(分+最大)/ 2;
INT比较=比较器(名单[MID]);
如果(比较== 0)
{
返回中旬;
}
如果(比较℃,)
{
分钟=中期+ 1;
}
,否则
{
最大=年年1;
}
}
返回〜分钟;
}
老编辑:我会离开原来的回答以下,但这里有另外两个选项。
第一个需要从源数据投影到一个密钥类型,并指定键查找。比较本身就是在默认方式来完成该密钥类型:
公共静态INT BinarySearchBy< TSource,TKEY的>(本IList的< TSource>列表中,
Func键< TSource,TKEY的>投影,TKEY的键)
{
INT分钟= 0;
INT最大= list.Count-1;
,而(分钟< =最大值)
{
INT中旬=(分+最大)/ 2;
TKEY的midKey =预测(表[MID]);
INT比较=的Comparer< TKEY的> .Default.Compare(midKey,键);
如果(比较== 0)
{
返回中旬;
}
如果(比较℃,)
{
分钟=中期+ 1;
}
,否则
{
最大=年年1;
}
}
返回〜分钟;
}
第二个需要一个Func键代替,将项目从与该列表进行比较关键我们要寻找的。该代码是几乎完全一样,当然 - 这只是它改变了对比:
公共静态INT BinarySearchBy< TSource,TKEY的> (这个IList的< TSource>列表中,
Func键< TSource,TKEY的,INT>比较器,TKEY的键)
{
INT分钟= 0;
INT最大= list.Count-1;
,而(分钟< =最大值)
{
INT中旬=(分+最大)/ 2;
INT比较=比较器(名单[MID],键);
如果(比较== 0)
{
返回中旬;
}
如果(比较℃,)
{
分钟=中期+ 1;
}
,否则
{
最大=年年1;
}
}
返回〜分钟;
}
这些都是未经检验的,但至少编译:)
原来的答复:
您可以使用列表< T&取代。二分查找
与的IComparer< T>
。你不必写自己的实现的IComparer<的; T>
- 我在的 MiscUtil 它建立一个的IComparer< T>
从比较< T>
代表。只有斑点前三个条件,但二进制搜索将制定出从休息的最后一个。
在事实上,代码是如此短暂我还不如贴。在这里(没有评论,无可否认)
公共密封类ComparisonComparer< T> :的IComparer< T>
{
只读比较< T>比较;
公共ComparisonComparer(比较< T>比较)
{
如果(比较== NULL)
{
抛出新的ArgumentNullException(比较) ;
}
this.comparison =比较;
}
公众诠释比较(T X,T Y)
{
收益比较(X,Y);
}
}
所以,你可能做这样的事情:
VAR比较器=新ComparisonComparer<&人GT;((P1,P2)=> p1.ID.CompareTo(p2.ID));
INT指数= list.BinarySearch(员工,比较器);
MiscUtil也有一个 ProjectionComparer
你可能会感兴趣的 - 你只需指定投影,就像排序依据
使用LINQ - 但它实际上取决于你的使用情况
I have a List<T>
that I want to search not for a given item but for an item satisfying a given condition. Given an item in the list I can test which of 4 conditions is true:
- the desired item must be to the left
- the desired item must be to the right
- this is the desired item
- the desired can't be in the list
A quick glance at the list functions was not encouraging so I'm wondering if anyone knows off a function I can use?
Edit: this is a local temp list so I known that it will be sorted correctly
Edit: BinarySearch looks almost right but in my case I don't have an item to compare with. I'd use Jon Skeet's solution and ignore one arg, but I'm not sure that I can count on it always being the same arg.
New edit: I'll leave the extra binary searches below, as they'll be useful for others, and here's a final option which is I think what you actually want. Your delegate should return a positive number if the item it's looking for is "less than" the one specified, a negative number if it's "greater than" the one specified, and 0 if it's just right.
public static int BinarySearchForMatch<T>(this IList<T> list,
Func<T,int> comparer)
{
int min = 0;
int max = list.Count-1;
while (min <= max)
{
int mid = (min + max) / 2;
int comparison = comparer(list[mid]);
if (comparison == 0)
{
return mid;
}
if (comparison < 0)
{
min = mid+1;
}
else
{
max = mid-1;
}
}
return ~min;
}
Old edit: I'll leave the original answer below, but here are two other options.
The first takes a projection from the source data to a key type, and specifies the key to find. The comparison itself is just done in the default way for that key type:
public static int BinarySearchBy<TSource,TKey>(this IList<TSource> list,
Func<TSource,TKey> projection, TKey key)
{
int min = 0;
int max = list.Count-1;
while (min <= max)
{
int mid = (min + max) / 2;
TKey midKey = projection(list[mid]);
int comparison = Comparer<TKey>.Default.Compare(midKey, key);
if (comparison == 0)
{
return mid;
}
if (comparison < 0)
{
min = mid+1;
}
else
{
max = mid-1;
}
}
return ~min;
}
The second takes a Func instead, to compare an item from the list with the key we're looking for. The code is almost exactly the same, of course - it's just the comparison which changes:
public static int BinarySearchBy<TSource,TKey>(this IList<TSource> list,
Func<TSource,TKey,int> comparer, TKey key)
{
int min = 0;
int max = list.Count-1;
while (min <= max)
{
int mid = (min + max) / 2;
int comparison = comparer(list[mid], key);
if (comparison == 0)
{
return mid;
}
if (comparison < 0)
{
min = mid+1;
}
else
{
max = mid-1;
}
}
return ~min;
}
These are both untested, but do at least compile :)
Original answer:
You can use List<T>.BinarySearch
with an IComparer<T>
. You don't have to write your own implementation of IComparer<T>
- I've got on in MiscUtil which builds an IComparer<T>
from a Comparison<T>
delegate. That only spots the first three conditions, but the binary search will work out the last one from the rest.
In fact, the code is so short I might as well paste it here (sans comments, admittedly).
public sealed class ComparisonComparer<T> : IComparer<T>
{
readonly Comparison<T> comparison;
public ComparisonComparer(Comparison<T> comparison)
{
if (comparison == null)
{
throw new ArgumentNullException("comparison");
}
this.comparison = comparison;
}
public int Compare(T x, T y)
{
return comparison(x, y);
}
}
So you might do something like:
var comparer = new ComparisonComparer<Person>((p1, p2) => p1.ID.CompareTo(p2.ID));
int index = list.BinarySearch(employee, comparer);
MiscUtil also has a ProjectionComparer
you might be interested in - you just specify a projection, just like in OrderBy
with LINQ - but it really depends on your use case.
这篇关于采用委托条件的二进制搜索一个C#列表的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!