使用Lambda按字母A-L和M-Z排序

时间:2019-05-15 02:26:58

标签: c# list entity-framework linq lambda

美好的一天,

在我的示例场景中,我试图从数据库中获取所有用户,然后将其放置在dto上,该dto上具有按字母顺序排序的列表,给出以下内容:A-L,M-Z

这是我的示例代码,用户名公用OrderBy

var users = await users.Users().ToListAsync();

return users.Select(u=>new CategorizedByLetterUserDto{
    ...
}).OrderBy(u=>u.Name);

所以我的示例CategorizedByLetterUserDto看起来像这样。

public class CategorizedByLetterUserDto {
     public IEnumerable<AtoL> AtoL {get;set}    
     public IEnumerable<MtoZ> MtoZ {get;set;}
     ...
}

public class AtoL{
     public int Id {get;set;}
     public string Name {get;set;}
}

public class MtoZ{
     public int Id {get;set;}
     public string Name {get;set;}
}

so on and so forth...

所以结果将是(数组)

 {
     categorizedByLetterUserDto: {
         atoL: [
         {
           ...
         }
         ],
         mtoZ: [
         {
           ...
         }
         ]
     }
 }

3 个答案:

答案 0 :(得分:2)

使用GroupBy,如下所示:

 var grouped = users.GroupBy(u => u.Name.CompareTo("M") < 0).OrderBy(g => g.Key).ToArray();
 return new CategorizedByLetterUserDto
 {
    AtoL = grouped[1].Select(x => new UserDto { Id = x.Id, Name = x.Name }),
    MtoZ = grouped[0].Select(x => new UserDto { Id = x.Id, Name = x.Name }),
 };

不要创建相同的类,请使用:

public class UserDto
{
    public int Id {get;set;}
    public string Name {get;set;}
}

您可以改用ToLookup,在这种情况下,它是等效的,但有关何时不可用的详细信息,请参见https://stackoverflow.com/a/10215531/224370

如果要在多个拆分点上拆分,可以执行以下操作:

string splits = "EMT";
var grouped = users.GroupBy(u => splits.Count(c => u.Name[0] > c))
                     .OrderBy(g => g.Key).ToArray(); ...

注意:纯粹主义者倾向于使用分割字符的排序列表和二进制搜索方法来查找索引,但是对于大多数实际的较小分割字符集,这样做会更快,代码更少,并且不在乎排序的顺序分割点在其中指定。

答案 1 :(得分:0)

在您的CategorizedByLetterUserDto类中最好使用List <>类而不是IEnumerable <>来访问.Add方法。然后尝试ff代码。

var users = await users.Users().ToListAsync();
char[] listOfAtoL = "ABCDEFGHIJKL".toCharArray();
CategorizedByLetterUserDto cat = new CategorizedByLetterUserDto();

foreach (User u in users.OrderBy(a => a.Name)) {
    listOfAtoL.Contains(char.ToUpper(u.Name.toCharArray()[0])) ? cat.AtoL.Add(new AtoL() {id = u.ID, Name = u.Name}) : cat.MtoZ.Add(new MtoZ() {id = u.ID, Name = u.Name});
}

return cat;

答案 2 :(得分:0)

我认为您不需要参与其中,您可以使用LINQ的现有功能来创建查找

List<User> list = ... .OrderBy(u=>u.Name); //from db 

ILookup<int, User> lookup = list.ToLookup(
  u => (u.Name[0] - 63)/14,
  u => new Dto { Id = u.Id, Name = u.Name }
);

数字与在ascii表中将char当作int对待,A为65。通过减去63,A变为2,L变为13,Z变为27。然后除以14,我们将其减为0或1现在,您的查询将是被0或1索引的用户的枚举,0是AtoL。如果要对给定列表中的用户进行排序,可以对其调用OrderBy。我是通过数学而不是布尔比较来完成此操作的,因此您将来可以通过更改数字将其更改为更多列,但是您也可以使用布尔:

var lookup = list.ToLookup(
  u => u.Name[0]<'M',
  u => new Dto { Id = u.Id, Name = u.Name }
);

在此返回的查询中,索引为true的索引将是A到L

分配给您已分类的Dto:

var x = new CatDto(){ 
  aToL=lookup[true],   
  mToZ=lookup[false] 
};

请注意,这与此处的所有其他答案结合在一起,取决于您的姓名格式正确,并使用大写ASCII字符作为第一个字符。如果您的姓名混乱,或者不一定总是以此开头,则应考虑做类似比较之前的大写等操作