我在内存中有一个字符串列表,其中包含两项:"product 1 max"one_answers"product 2 min"。当用户输入为"产品分钟"时,我如何搜索并获得"产品1分钟"?
注意,中间有一些漏字。
var list = new List<string> {"product 1 max", "product 1 min" };
//user input 'product min' and he expected 'product 1 min'
如果将输入拆分为单词,则可以将list
筛选为包含所有输入单词的匹配项:
var inputWords = input.Split(' ');
var ans = list.Where(s => inputWords.All(s.Contains)).ToList();
注:s.Contains
是一种更短、更有效(更模糊(的w => s.Contains(w)
方法
一种方法是分割输入并将其与字符串列表中的每个单词匹配。
var list = new List<string> { "product 1 max", "product 1 min" };
var input = "product min";
List<string> inputParts = input.Split(' ').ToList();
// contains all the input strings
List<string> results = list.Where(x => x.Split(' ').Intersect(inputParts).Count() == inputParts.Count).ToList();
// partial matching strings
List<string> partialMatches = list.Where(x => x.Split(' ').Intersect(inputParts).Count() > 0).ToList();
关于Intersect方法的文档可以在这里找到
实现这一点的一种方法是使用Damerau-Levenstein算法。这是一种基本上计算一个字符串需要多少更改的算法,它可以手动实现,但有点棘手,而且已经有一个库(SoftWx.Match(为您封装了逻辑。
Match有一个名为DamerauOSA(string value1, string value2)
的静态方法,它返回一个介于0和1之间的double
,告诉你这两个字符串有多像,你可以很容易地将其与LINQ混合。
List<string> products = new List<string>()
{
"product 1 max",
"product 1 min"
};
var stringToCompare = "product min";
products.ForEach(x => Console.WriteLine($"Item {x} against {stringToCompare} has {Similarity.DamerauOSA(x, stringToCompare)} points of similarity"));
// 0.80 is an arbitrary number of how much "equality" you want from both strings
var filtered = products.Where(x => Similarity.DamerauOSA(x, stringToCompare) > 0.80).ToList();
Console.WriteLine("Filtered");
filtered.ForEach(x => Console.WriteLine(x));
此处的工作示例