采用委托条件的二进制搜索一个C#列表 [英] Binary search of a C# list using delegate condition

查看:208
本文介绍了采用委托条件的二进制搜索一个C#列表的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个列表< 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆