使用排名优化集合中的搜索

时间:2015-07-29 09:30:44

标签: c#

我要根据某些逻辑执行一些收集和返回排名 我希望优化这个工作代码,因为我认为它可以更好(可能使用任务?)

这是执行搜索的代码和扩展方法

public class Counterpart
{
    public int Id { get; set; }

    public string Code { get; set; }

    public string Description { get; set; }

    public IEnumerable<Alias> Aliases { get; set; }

    public override bool Equals(object obj)
    {
        Counterpart obj2 = obj as Counterpart;
        if (obj2 == null) return false;
        return Id == obj2.Id;
    }
}

public class Alias
{
    public int? Type { get; set; }

    public string Description { get; set; }
}

internal class CounterPartRanking
{
    public int Rank { get; set; }

    public Counterpart CounterPart { get; set; }
}

public static class CounterpartExtensions
{
    public static IEnumerable<Counterpart> SearchWithRank(this IEnumerable<Counterpart> source, string pattern)
    {
        var items1 = source.Where(x => x.Code == pattern);
        var items2 = source.Where(x => x.Code.StartsWith(pattern));
        var items3 = source.Where(x => x.Code.Contains(pattern));
        var items4 = source.Where(x => x.Description.Contains(pattern));
        var items5 = source.Where(x => x.Aliases != null && x.Aliases.Any(y => y.Description == pattern));
        var items6 = source.Where(x => x.Aliases != null && x.Aliases.Any(y => y.Description.StartsWith(pattern)));
        var items7 = source.Where(x => x.Aliases != null && x.Aliases.Any(y => y.Description.Contains(pattern)));

        Stopwatch sw = Stopwatch.StartNew();
        var rankedItems = new List<CounterPartRanking>();


        if (items1.Any())
            rankedItems.AddRange(items1.Select(x => new CounterPartRanking { Rank = 1, CounterPart = x }));
        if (items2.Any())
            rankedItems.AddRange(items2.Select(x => new CounterPartRanking { Rank = 2, CounterPart = x }));
        if (items3.Any())
            rankedItems.AddRange(items3.Select(x => new CounterPartRanking { Rank = 3, CounterPart = x }));
        if (items4.Any())
            rankedItems.AddRange(items4.Select(x => new CounterPartRanking { Rank = 4, CounterPart = x }));
        if (items5.Any())
            rankedItems.AddRange(items5.Select(x => new CounterPartRanking { Rank = 5, CounterPart = x }));
        if (items6.Any())
            rankedItems.AddRange(items6.Select(x => new CounterPartRanking { Rank = 6, CounterPart = x }));
        if (items7.Any())
            rankedItems.AddRange(items7.Select(x => new CounterPartRanking { Rank = 7, CounterPart = x }));

        sw.Stop();

        Debug.WriteLine("Time elapsed {0} for {1}", sw.Elapsed, pattern);
        var items = rankedItems.OrderBy(x => x.Rank).Select(x => x.CounterPart);
        var distinct = items.Distinct();

        return distinct;
    }
}

有什么建议吗? 感谢

3 个答案:

答案 0 :(得分:0)

利用Contains(pattern)StartsWith(pattern)== pattern越来越具体的子集这一事实会有所帮助:

即。

var items3 = source.Where(x => x.Code.Contains(pattern));
var items2 = items3.Where(x => x.Code.StartsWith(pattern));
var items1 = items2.Where(x => x.Code == pattern);

应该导致比每次检查source整个

更少的比较

答案 1 :(得分:0)

看看这是否提高了性能

   public static class CounterpartExtensions
    {
        public static IEnumerable<Counterpart> SearchWithRank(this IEnumerable<Counterpart> source, string pattern)
        {
            Stopwatch sw = Stopwatch.StartNew();
            var rankedItems = new List<CounterPartRanking>();

            foreach (Counterpart counterpart in source)
            {
                if ((counterpart.Code != null) && (counterpart.Code == pattern))
                {
                    rankedItems.AddRange(new CounterPartRanking { Rank = 1, CounterPart = counterpart });
                }
                else
                {
                    if ((counterpart.Code != null) && (counterpart.Code.StartsWith(pattern)))
                    {
                        rankedItems.AddRange(new CounterPartRanking { Rank = 2, CounterPart = counterpart });
                    }
                    else
                    {
                        if ((counterpart.Code != null) && (counterpart.Code.Contains(pattern) == pattern))
                        {
                            rankedItems.AddRange(new CounterPartRanking { Rank = 3, CounterPart = counterpart });
                        }
                    }
                }
               if ((counterpart.Description != null) && (counterpart.Description.Contains(pattern) == pattern))
                {
                    rankedItems.AddRange(new CounterPartRanking { Rank = 4, CounterPart = counterpart });
                }
               if ((counterpart.Aliases != null) && (counterpart.Aliases == pattern))
               {
                   rankedItems.AddRange(new CounterPartRanking { Rank = 5, CounterPart = counterpart });
               }
               else
               {
                   if ((counterpart.Aliases != null) && (counterpart.Aliases.StartsWith(pattern)))
                   {
                       rankedItems.AddRange(new CounterPartRanking { Rank = 6, CounterPart = counterpart });
                   }
                   else
                   {
                       if ((counterpart.Aliases != null) && (counterpart.Aliases.Contains(pattern)))
                       {
                           rankedItems.AddRange(new CounterPartRanking { Rank = 7, CounterPart = counterpart });
                       }
                   }
               }
            }


            sw.Stop();

            Debug.WriteLine("Time elapsed {0} for {1}", sw.Elapsed, pattern);
            var items = rankedItems.OrderBy(x => x.Rank).Select(x => x.CounterPart);
            var distinct = items.Distinct();

            return distinct;
        }
    }

答案 2 :(得分:0)

我喜欢这种方法:

public static IEnumerable<Counterpart> SearchWithRank(this IEnumerable<Counterpart> source, string pattern)
{
    var sources = new []
    {
        source.Where(x => x.Code == pattern),
        source.Where(x => x.Code.StartsWith(pattern)),
        source.Where(x => x.Code.Contains(pattern)),
        source.Where(x => x.Description.Contains(pattern)),
        source.Where(x => x.Aliases != null && x.Aliases.Any(y => y.Description == pattern)),
        source.Where(x => x.Aliases != null && x.Aliases.Any(y => y.Description.StartsWith(pattern))),
        source.Where(x => x.Aliases != null && x.Aliases.Any(y => y.Description.Contains(pattern))),
    };

    Stopwatch sw = Stopwatch.StartNew();

    var rankedItems =
        sources
            .SelectMany((x, n) => x.Select(y => new CounterPartRanking { Rank = n + 1, CounterPart = y }))
            .ToList();

    sw.Stop();

    Debug.WriteLine("Time elapsed {0} for {1}", sw.Elapsed, pattern);
    var items = rankedItems.OrderBy(x => x.Rank).Select(x => x.CounterPart);
    var distinct = items.Distinct();

    return distinct;
}

它可能不会更快,但它更简洁的代码。在我的书中,这种方式更好。