我们假设我们收集了Human
s:
public class Human
{
public string FirstName { get; set; }
public string SecondName { get; set; }
public string CompanyName { get; set; }
}
var people = new List<Human>(){...};
我们如何在首先按FirstName
然后按SecondName
然后按CompanyName
对人进行排序时实施自动完成功能?
我试过了:
people.Where(x => x.FirstName.StartsWith(term) || x.SecondName.StartsWith(term)
|| x.CompanyName.StartsWith(term))
.OrderBy(x => x.FirstName).ThenBy(x => x.SecondName).ThenBy(x => x.CompanyName)
但这并不能正常工作。我想首先只查看所有匹配的FirstName
字段,然后只查看SecondName
个字段,依此类推。
答案 0 :(得分:4)
people.Where(x => x.FirstName.StartsWith(term)).OrderBy(x => x.FirstName)
.Concat(people.Where(x => x.SecondName.StartsWith(term)).OrderBy(x => x.SecondName))
.Concat(people.Where(x => x.CompanyName.StartsWith(term)).OrderBy(x => x.CompanyName))
根据您是否要排除一个人匹配的情况多于一种情况,将.Distinct()
添加到最后(在这种情况下,您也可以使用.Union()
代替{{1}取决于您的来源 - 它被记录为保留具有可枚举源的顺序,但不记录其他可查询源,因此它可能会根据.Concat()
的来源搞乱排序。
答案 1 :(得分:2)
我想你会想要
people.Where(x => x.FirstName.StartsWith(term) ||
x.SecondName.StartsWith(term) ||
x.CompanyName.StartsWith(term))
.OrderByDescending(x => x.FirstName.StartsWith(term))
.ThenByDescending(x => x.SecondName.StartsWith(term))
.ThenBy(x => x.FirstName)
.ThenBy(x => x.SecondName)
.ThenBy(x => x.CompanyName)
这就是
当Descending
小于false
时,是/否排序需要true
。
你可以通过{{1}使用一个匿名类和Select
,FirstNameMatches
等三个bool来稍微优化一下,然后在{{1}中使用这些bool和订购子句,从而避免调用SecondNameMatches
5次而不是3次,但是当你对基本排序工作时你可以担心。
如果你想用秒名对第二名匹配进行排序,公司名称按公司名称匹配,那将会更加棘手。
答案 2 :(得分:2)
您所犯的错误是您在ThenBy()
之后使用OrderBy()
。使用此方法,您可以在内部对已经排序的列表进行重新排序,而无需根据属性是否匹配进行排序。
您应该做的是以三种方式过滤列表,然后加入它们并使用Union()
删除重复项。
那么:
people.Where( x => x.FirstName.StartsWith( term ) ).OrderBy( x => x.FirstName )
.Union( people.Where( x => x.SecondName.StartsWith( term ) ).OrderBy( x => x.SecondName ) )
.Union( people.Where( x => x.CompanyName.StartsWith( term ) ).OrderBy( x => x.CompanyName ) );
编辑:
正如 Jon Hanna 指出的那样,如果您使用Queryable.Union()
,这可能无效,因为它不会保留查询的顺序:
Enumerable.Union()被指定为保留顺序但是 Queryable.Union()不是。给定的实现可以,但事实并非如此 必须和另一个(或对同一个的更新)可能不会。代码 因此,如果有人,可以按任何顺序给出结果 不是内存中的来源。 Jon Hanna