Прошло уже пару дней, пытаясь выяснить, какой самый эффективный способ поиска списка списков с тысячами элементов с несколькими ключевыми словами без определенного порядка. Я реализовал простой поиск на других экранах, но это немного сложно. Позволь мне объяснить.
поэтому давайте скажем, что мои списки выглядят следующим образом:
и если я наберу в поле поиска ключевое слово "человек", я ожидаю увидеть 3 удара, что легко выполнить. Однако, если я набираю частичные ключевые слова, такие как "ma" или "ma a", я ожидаю увидеть только управление гневом. Если есть более одного удара, я должен уметь сузить его, набрав больше слов или просто заполнив свои ключевые слова, которые у меня есть в окне поиска.
Сейчас у меня есть реализация, но я не слишком доволен ею из-за количества итераций, которые я делаю. Я боюсь, что, когда у нас будет больше данных, этот поиск не будет работать эффективно и будет медленным.
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 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(' ');
Вы можете получить результаты поиска в 1 выстреле следующим образом:
var results = filmCategories
.SelectMany(category => category.Films)
.Where(film =>
searchTerms.All(term =>
film.ToLower().Split(' ')
.Any(word =>
word.StartsWith(term))));
Очень маловероятно, что производительность будет проблемой, если в ваших списках нет миллионов элементов. Вы всегда должны измерять фактическую производительность использования, прежде чем пытаться оптимизировать.
В любом случае ваш код упрощается до этого:
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();
}
Это не кажется слишком плохим. Единственное, что выделяется, это то, что вы возвращаете только те элементы, которые "содержат" и "начинают с" термины перевода, но это означает, что вы возвращаете только те элементы, которые "начинаются с", и игнорируют все, что "содержит". Это может потребоваться переосмысление.
Теперь вы можете пойти дальше и упростить свой код:
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();
}
.ToLowerInvariant()
по мере необходимости.