针对列表列表的多个搜索关键字

时间:2014-06-02 23:49:42

标签: c# .net wpf search mvvm

现在已经花了几天时间试图找出哪种搜索列表列表的最有效方法,其中包含数千个具有多个关键字且无特定顺序的项目。我已经在其他屏幕上实现了简单的搜索,但这个有点棘手。让我解释一下。

所以我可以说我的列表如下所示

  1. 武术
    • 死亡游戏
    • 知识产权人
    • 保护者
  2. 喜剧
    • 骑行
    • 警察学院
    • 主持人
    • 愤怒管理
  3. 动作
    • 血与骨
    • The Matrix
    • 美国队长
    • 终结者
  4. 如果我在搜索框中键入关键字" man",我希望看到3次点击,这很容易实现。但是,如果我键入部分关键字,例如" ma"或者" ma a"我希望只看到Anger Management。如果有多个匹配,那么我应该可以通过输入更多字词或只是填写搜索框中的关键字来缩小范围。

    现在我有一些实现,但由于我正在进行的迭代次数,我对它不太满意。我担心当我们有更多数据时,这种搜索不会有效地执行并且会很慢。

    public List<ValidAndCompletedModel> Filter(List<string> searchTerms)
    {
        var validAndCompleted = new List<ValidAndCompletedModel>();
    
        foreach (var searchTerm in searchTerms)
        {
            var containingList = ValidAndCompleted.Where(d => ListsContainsSimilarEntry(searchTerm, d.EnglishTranslationTerms)).ToList();
            containingList = containingList.Distinct().ToList();
            validAndCompleted.AddRange(containingList.Where(d => ListsStartsWithSimilarEntry(searchTerm, d.EnglishTranslationTerms)).ToList());
        }
        validAndCompleted = validAndCompleted.Distinct().ToList();
    
    
        return validAndCompleted;
    }
    
    private bool ListsStartsWithSimilarEntry(string searchTerm, IEnumerable<string> searchList)
            {
                var available = searchList.Any(sl => sl.StartsWith(searchTerm));
                return available;
            }
    private bool ListsContainsSimilarEntry(string searchTerm, IEnumerable<string> searchList)
                {
                    var available = searchList.Any(sl => sl.Contains(searchTerm));
                    return available;
                }
    

    非常感谢您的帮助。

2 个答案:

答案 0 :(得分:0)

除非您的列表中包含数百万个项目,否则性能不太可能成为问题。在尝试优化之前,您应该始终测量实际使用情况。

无论如何,您的代码简化为:

public List<ValidAndCompletedModel> Filter(List<string> searchTerms)
{
    return (
        from searchTerm in searchTerms
        from d in ValidAndCompleted
        where d.EnglishTranslationTerms.Any(sl => sl.Contains(searchTerm))
        where d.EnglishTranslationTerms.Any(sl => sl.StartsWith(searchTerm))
        select d)
            .Distinct()
            .ToList();
}

这似乎太糟糕了。唯一突出的是你只返回了包含&#34;包含&#34;和&#34;从&#34;开始翻译条款,但这意味着您只返回&#34;以&#34;开头的项目。并忽略任何&#34;包含&#34;。这可能需要重新考虑。

现在你可以进一步简化你的代码:

public List<ValidAndCompletedModel> Filter(List<string> searchTerms)
{
    return (
        from searchTerm in searchTerms
        from d in ValidAndCompleted
        from sl in d.EnglishTranslationTerms
        where sl.StartsWith(searchTerm)
        select d)
            .Distinct()
            .ToList();
}

或者你可以通过这样做完全避免.Distinct()调用(假设ValidAndCompleted列表中没有重复项):

public List<ValidAndCompletedModel> Filter2(List<string> searchTerms)
{
    return ValidAndCompleted
        .Where(d => (
            from searchTerm in searchTerms
            from sl in d.EnglishTranslationTerms
            where sl.StartsWith(searchTerm)
            select d).Any())
        .ToList();
}

答案 1 :(得分:0)

使用你的电影&amp;类别示例。假设我们有这样一个类:

public class Category
{
    public string Name {get; set;}
    public List<string> Films {get; set;}
}

我们的电影设置如下:

var filmCategories = new List<Category>
{
new Category { Name = "Martial Arts", Films = new List<string>
        { "Game Of Death", "IP Man", "The Protector" }},            
    new Category { Name = "Comedy", Films = new List<string>
        { "Ride Along", "Police Academy", "Anchorman", "Anger Management" }},           
    new Category { Name = "Action", Films = new List<string>
        { "Blood And Bone", "The Matrix", "Captain America", "The Terminator" }}
};  

我们的搜索字词如下:

var searchTerm = "g d";
var searchTerms = searchTerm.ToLower().Split(' ');

您可以像这样一次拍摄搜索结果:

var results = filmCategories
    .SelectMany(category => category.Films)
    .Where(film => 
        searchTerms.All(term =>
            film.ToLower().Split(' ')
            .Any(word =>            
                word.StartsWith(term))));