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

本文关键字:列表 关键字 搜索 | 更新日期: 2023-09-27 18:06:34

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

让我们假设我的列表看起来像下面的

  1. 武术
    • 死亡游戏
    • 叶问
    • 保护器
  2. 喜剧
    • 警察学院
    • 主持人
    • 愤怒管理
  3. 行动
    • 血与骨
    • 这个矩阵
    • 美国队长
    • 《终结者》

,如果我在搜索框中输入关键字"man",我希望看到3个命中,这很容易实现。然而,如果我输入部分关键字,如"妈"或"妈",我希望只看到愤怒管理。如果有不止一个匹配,那么我应该能够通过输入更多的单词或简单地完成我在搜索框中的关键词来缩小范围。

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

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

非常感谢您的帮助

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

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

在任何情况下,你的代码都简化成这样:

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

那似乎不太坏。唯一值得注意的是,您只返回"包含"answers"以"翻译术语开始的项,但这意味着您只返回"以"开始的项,而忽略任何"包含"的项。这可能需要重新考虑。

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

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

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

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