如何根据员工收入中员工薪水排名第二的基于身份证的LINQ选择不同的员工?

问题描述 投票:3回答:4

请看下面的例子。这里员工ID = 2又名史蒂夫有3个重复。我只想要每个ID的一条记录。我想选择薪水第二高的记录。因此,在史蒂夫的情况下,选择将是两个史蒂夫帽子中的一个有160作为薪水。

       public class Employee
        {
            public int ID { get; set; }
            public string Name { get; set; }
            public int Salary { get; set; }

            public static List<Employee> GetAllEmployees()
            {
                return new List<Employee>()
        {
            new Employee { ID = 1, Name = "Mark", Salary = 100 },
            new Employee { ID = 2, Name = "Steve", Salary = 150 },
            new Employee { ID = 2, Name = "Steve", Salary = 160 },
            new Employee { ID = 2, Name = "Steve", Salary = 160 },
            new Employee { ID = 2, Name = "Steve", Salary = 165 },
            new Employee { ID = 3, Name = "Ben", Salary = 140 }                

        };
            }
        }

期望的输出:

1 Mark 100
1 Steve 160 //2nd highest salary of steve( there are two such steves so pick any)
1 Mark 100
1 Ben 140 

我知道如何根据属性获取不同的记录:

var result = Employee.GetAllEmployees().GroupBy(x=>x.ID).Distinct();

但我在另一方面迷失了方向。

请注意我只是在寻找LINQ lambda /扩展语法的答案。谢谢!

c# .net linq
4个回答
2
投票

一种方法是在Select之后使用GroupBy。这将把每个小组变成一个雇员。

Employee.GetAllEmployees().GroupBy(x=>x.ID).Select(x => FindSecondHighest(x));

其中FindSecondHighest应该是这样的:

private static Employee FindSecondHighest(IEnumerable<Employee> employees) {
    var list = employees.ToList();
    if (list.Count == 1) { return list[0]; }
    return list.OrderByDescending(x => x.Salary).Skip(1).First();
}

如果你愿意,你可以将方法重写为lambda,但我觉得这样的方式更具可读性。

编辑:

我意识到,如果有两个最高的工资,这实际上并没有获得第二高薪。要实际获得第二高的薪水,你可以使用第二个GroupBy

private static Employee FindSecondHighest(IEnumerable<Employee> employees) {
    var list = employees.ToList();
    if (list.Count == 1) { return list[0]; }
    return list.GroupBy(x => x.Salary).OrderByDescending(x => x.Key).Skip(1).First();
}

2
投票

首先,失去Distinct()。根据定义,分组是唯一的。

根据您的要求,您需要按工资(降序)订购分组结果,然后选择第二个。仅在分组具有多个项目时执行此操作。由此产生的结果应该是:

    var result = Employee.GetAllEmployees()
        .GroupBy(x => x.ID)
        .Select(x => (x.Count() > 1 ? x.GroupBy(y => y.Salary).Skip(1).Select(y => y.First()) : x).First()
        );

编辑:根据评论更新我的答案,我们需要按工资分组,然后跳过1以缓解第二条记录也具有最高薪水值的情况。


0
投票

以下应该有效:

Employee.GetAllEmployees().Where(x => {
    recordsWithID = Employee.GetAllEmployees().Where(y => y.ID == x.ID).OrderByDescending(y => y.Salary);

    recordToReturn = recordsWithID.Count > 1 ? recordsWithID.Skip(1).First() : recordsWithID.First();

    return x.ID == recordToReturn.ID;
});

首先,在主谓词中,我们选择具有x的ID的所有用户。然后,如果有多个具有该ID的记录,我们获得具有第二高薪水的记录,否则,我们只选择具有该ID的唯一记录。然后,如果对于x的ID组,x是实际所需的记录(因此x只有一个带有其ID或x在具有x的ID的记录中具有第二高的薪水),则返回x,否则不返回。

我目前无法测试这个,因为我不在电脑前,但这应该给你一个想法。


0
投票

你可以尝试使用.GroupBy.Select这样的东西:

static void Main(string[] args)
{
    List<Employee> secondHighestSalaryPersons = Employee.GetAllEmployees()
         .GroupBy(x => x.Name)
         .Select(x =>
         {
             var group = x.ToList();

             if (group.Count > 1)
                 return group.OrderByDescending(y => y.Salary).Skip(1).FirstOrDefault();
             else
                 return group.FirstOrDefault();
         })
         .ToList();
}
© www.soinside.com 2019 - 2024. All rights reserved.