我正在实施“搜索”自动完成功能。我想返回一个按用户提交的字符顺序排序的结果列表,其中排序结果顶部的项目是字符串中第一个到 n 个字符中的字符的项目。
有没有一种优雅的方法可以使用 LINQ 做到这一点?
例如,假设当用户键入“un”时,从数据库中返回以下项目。
- 美国德克萨斯州
- 美国佛罗里达州
- 美国纽约
- 美国
我想返回排序结果显示如下:
- 美国
- 美国德克萨斯州
- 美国佛罗里达州
- 美国纽约
请注意,“un”上方的每个字符串都位于位置 1-2、7-8、10-11 和 11-12。
一般来说,@HugoRune 的答案会起作用,但有两个问题有点低效。
使用ToLower()
导致所有字符串首先转换为小写,即使第一个字符的比较表明它们不匹配。
我们进行了两次基本相同的比较。一次Contains()
和一次IndexOf()
。所以我们遍历字符串两次。
以下代码的效率至少是原来的两倍:
IEnumerable<string> stateNames= [your source here];
string searchString="un";
var result =
stateNames
.Select(state=> new {Name=state, Index = state.IndexOf(searchString, StringComparison.CurrentCultureIgnoreCase)})
.Where(tuple=>tuple.Index>=0)
.OrderBy(tuple=>tuple.Index)
.Select(tuple=>tuple.Name);
您可以使用 IndexOf 获取子字符串的位置,并且可以在 OrderBy 子句中使用该索引
(以下假设您有一个带有“名称”列的数据库表“States”)
var result = dc.States
.Where(s=>s.Name.ToLower().Contains("un"))
.OrderBy(s=>s.Name.ToLower().IndexOf("un"));
或者一个简单的缓存解决方案,如果你不想每次都访问数据库:
// call this once during initialisation
List<States> cachedStates =
dc.States.ToList();
...
// call this every time
var result = cachedStates
.Where(s=>s.Name.ToLower().Contains("un"))
.OrderBy(s=>s.Name.ToLower().IndexOf("un"));
我对实现自动完成功能的建议是在应用程序加载和缓存时按名称升序排列所有国家名称及其 id。现在,无论何时用户键入它都应该使用此缓存结果集进行匹配,使用 linq 查询。获得更好性能的另一个调整是在您的情况下使用最少字符,例如 2,然后只进行 linq 查询
采用这种方式的原因:您只需访问数据库一次即可获取所有国家/地区名称,而不是每个字符的键位。请注意,并非每天都会更改国家/地区,因此您的缓存只能在应用程序重新启动时过期。
希望这可以帮助
使用CompareTo
方法如下:
SomeContext.ACollection.Where(...).OrderBy(x=> searchTerm.CompareTo(x) > 0)
CompareTo 方法返回一个整数,表示比较字符串将按字符顺序排序的位置。