Linq-选择中的优选值

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Linq-选择中的优选值相关的知识,希望对你有一定的参考价值。

如果我有以下型号:

Public class Person {
  public string Name {get; set;}
  public string Type {get; set;}
  public int Salary {get; set;}
}

我有一份人员名单,List<Person> persons = new List<Person>();

现在我想要最常见的经理薪水,如果不存在,我想要MiddleManagers最常见的薪水。

我尝试了以下方法:

int salary= persons.Where(x => x.Type=="Manager" || x.Type=="MiddleManager")
                    .GroupBy(pr => pr.Salary)
                    .OrderByDescending(g => g.Count())
                    .Select(x => x.Key)
                    .FirstOrDefault();

但这将返回经理和MiddleManagers中最常见的薪水,有没有办法实现上述目标而不会:

 int salary= persons.Where(x => x.Type=="Manager")
                        .GroupBy(pr => pr.Salary)
                        .OrderByDescending(g => g.Count())
                        .Select(x => x.Key)
                        .FirstOrDefault();
if(salary==0)
 salary= persons.Where(x => x.Type=="MiddleManager")
                        .GroupBy(pr => pr.Salary)
                        .OrderByDescending(g => g.Count())
                        .Select(x => x.Key)
                        .FirstOrDefault();

为什么我要避免上述情况?因为我对许多属性都有相同的逻辑。

答案

使用C#本地函数:

ILookup<string, Person> personsByType = persons.ToLookup(person => person.Type);

double getSalary(string type)
{
     return personsByType[type]
              .GroupBy(pr => pr.Salary)
              .OrderByDescending(g => g.Count())
              .Select(x => x.Key)
              .FirstOrDefault();
}

double salary= getSalary("Manager");
if (salary == 0)
{
    salary = getSalary("MiddleManager");
}

请注意,如果只有在没有给定类型的人的情况下才获得0工资,因为我认为某人不能拥有0工资。所以你可以这样做:

double? getSalary(string type)
{
   IEnumerable<Person> selectedPeople = personsByType[type];

   return selectedPeople.Any() ? selectedPeople
                                  .GroupBy(pr => pr.Salary)
                                  .OrderByDescending(g => g.Count())
                                  .Select(x => x.Key)
                                  .First()
                               : null;
}

double? salary= getSalary("Manager");
if (!salary.HasValue)
{
    salary = getSalary("MiddleManager");
}
另一答案

您可以检查是否存在与第一个条件匹配的Any项目,并将Type分配给将在查询中使用的字符串变量:

string property = persons.Any(x => x.Type == "Manager") ? "Manager" : "MiddleManager";

int salary = persons.Where(x => x.Type == property)
                .GroupBy(pr => pr.Salary)
                .OrderByDescending(g => g.Count())
                .Select(x => x.Key)
                .FirstOrDefault();

List<Person>中确切地说明这种分组逻辑的一种通用方法可能如下所示:

public int mostCommonSalary(List<Person> collection, params string [] types)
{
    foreach (var type in types)
    {
        if (collection.Any(x => x.Type == type))
        {
            return collection.Where(x => x.Type == type)
                    .GroupBy(pr => pr.Salary)
                    .OrderByDescending(g => g.Count())
                    .Select(x => x.Key)
                    .FirstOrDefault();
        }
    }   

    // nothing found
    return -1;
}

您可以根据需要使用多种类型。它的第一场比赛将被退回:

int salary = mostCommonSalary(persons,  "Manager", "MiddleManager", "MicroManager", "NanoManager");

通过传递您想要过滤的属性,可以使它更通用或更通用:

public int mostCommonSalaryGeneral<T>(List<Person> collection, 
                                      Func<Person, T> filterFunc,  params T[] types)
{
    foreach (var type in types)
    {
        if (collection.Any(x=> filterFunc(x).Equals(type)))
        {
            return collection.Where(x=> filterFunc(x).Equals(type))
                    .GroupBy(pr => pr.Salary)
                    .OrderByDescending(g => g.Count())
                    .Select(x => x.Key)
                    .FirstOrDefault();
        }
    }
    // nothing found
    return -1;
}

这样您就可以按所选属性进行过滤,并调用如下方法:

int salary = mostCommonSalaryGeneral(persons, p => p.Type, "Manager", "MiddleManager", "MicroManager", "NanoManager");
int salary = mostCommonSalaryGeneral(persons, p => p.Name, "Max", "Maxine", "Masud");
int salary = mostCommonSalaryGeneral(persons, p => p.SomeID, 1234, 3456);
另一答案

使用2种类型的简单循环,在循环体中使用Linq查询,或围绕Linq查询构建函数并使用不同类型调用它。例:

var salary = GetSalary(persons, "Manager");
if (salary == 0) salary = GetSalary(persons, "MiddleManager");

以上是关于Linq-选择中的优选值的主要内容,如果未能解决你的问题,请参考以下文章

错误 3002:映射片段中的问题 | c# linq 到实体

如果语句仅选择 linq2xml 查询中的第一个值

如何在文本区域标签中的特定光标位置插入选择标签下拉值作为文本片段?

LINQ 选择中的 C# 子查询

LINQ to XML - 从文件加载 XML 片段

LINQ 查询结果中的奇怪值