我有一个我希望在过滤时搜索的人员列表。 每次用户输入搜索字符串时,都会应用过滤。
需要考虑两个挑战:
通过搜索子串,可以简单地解决第一个问题。 String.Contains()。第二个可以通过使用模糊实现(例如https://fuzzystring.codeplex.com)
来解决但我不知道如何同时掌握这两项挑战。
例如:我想在进入其中一个时找到“Martin Fowler博士”的人:
我想我需要编写一个“FuzzyContains()”逻辑,它可以满足我的需求并具有可接受的性能。任何建议如何开始?
答案 0 :(得分:4)
似乎是Levenshtein距离算法(one of the dozens C# implementations)的工作。
您为此算法提供两个字符串(用户输入的字符串和列表中的一个字符串)。然后计算从第一个字符串到第二个字符串必须替换,添加或删除的字符数。然后,您可以从列表中获取距离小于或等于三的所有元素(例如),以找到简单的拼写错误。
如果你有这种方法,你可以这样使用它:
var userInput = textInput.Text.ToLower();
var matchingEmployees = EmployeeList.Where(x => x.Name.ToLower().Contains(userInput)
|| LevenshteinDistance.Compute(x.Name.ToLower(), userInput) <= 3)
.ToList();
答案 1 :(得分:3)
我修改了建议Levenshtein距离算法的Oliver answer,这不是这里的最佳选择,因为当只输入部分名称时计算的距离很大。所以,我最终使用了真棒Longest Common Subsequence algorithm实施的FuzzyString Lib。
const int TOLERANCE = 1;
string userInput = textInput.Text.ToLower();
var matchingPeople = people.Where(p =>
{
//Check Contains
bool contains = p.Name.ToLower().Contains(userInput);
if(contains) return true;
//Check LongestCommonSubsequence
bool subsequenceTolerated = p.Name.LongestCommonSubsequence(userInput).Length >= userInput.Length - TOLERANCE;
return subsequenceTolerated;
}).ToList();
答案 2 :(得分:1)
我之前已经完成了这项工作,并开始使用wikipedia approximate string matching中列出的一些方法。当我完成后,我调整了我的算法的方式不是通用的,但在我的域中给了我更好的匹配。
如果你的整个字典在内存中并且不是太大,你可以简单地对字典中的每个成员应用匹配算法。如果您的字典很大,这可能会过度使用您的资源,您将需要更好的算法。您可能还想考虑使用数据库的全文搜索功能。
在我的例子中,我迭代了我的字典中的每个字符串,比较“匹配运行”,即2个点用于2个字符匹配,3个用于3个字符匹配,最多8个字符匹配。我跑了所有可能的对,三元组等等 - 对每个词典条目进行评分并选择最高得分的比赛。容忍错别字,词序等,但计算成本高 - 我的词典只有几千个短语,所以这对我来说效果很好。这是Dice's coefficient.
的修改版本答案 3 :(得分:0)
但是从性能视图来看这可能是不可接受的。
答案 4 :(得分:0)
也许你可以使用这个soundex实现:CodeProject soundex做的是比较两个字符串并以百分比计算“发音相似度”。 前一段时间我借助这个函数构建了一个搜索(PHP hasit内置)
答案 5 :(得分:0)
我前段时间有一个上学项目,我们有一个文本框,学生可以搜索每个员工,学生与学校有关。我们谈论的是几百人。我们在Core i3处理器上使用的简单Linq查询非常快。每次用户在文本框中键入内容时都会调用该查询。在TextChanged事件中,我们调用了一个如下所示的查询:
var resultData = EmployeeList.Where(x=>x.Name.ToLower().Contains(textInput.Text.ToLower())).ToList();
当然,这个逻辑只适用于你有#34;博士。 Martin Fowler&#34;在一个财产或成员。
答案 6 :(得分:0)