用排序优化集合中的搜索

本文关键字:搜索 集合 排序 优化 | 更新日期: 2023-09-27 18:05:13

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

下面是我的代码和执行搜索的扩展方法
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;
    }
}

有什么建议吗?由于

用排序优化集合中的搜索

利用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更少的比较

看看这是否能提高性能

   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;
        }
    }

我喜欢这个方法:

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;
}

它可能不是更快,但它是更简洁的代码。在我看来,这样比较好。