仅当存在所有ID或更多ID时才在两个不同的列表对象之间找到匹配的ID?

时间:2018-12-26 16:59:55

标签: c# algorithm linq lambda

我在如何查找两个单独的List对象之间的匹配值方面遇到问题。目的是查找某个员工何时具有完成一项工作的全部或更多必需技能。

列表对象如下:

EmployeeSkills.cs

public int EMP_SKILL_ID { get; set; }
public int EMP_ID { get; set; }
public int SKILL_ID { get; set; }

SkillsRequired.cs

public int SKILL_REQ_ID { get; set; }
public int JOB_ID { get; set; }
public int SKILL_ID { get; set; }

我曾尝试使用Linq来寻找运气不佳的比赛,我还尝试了一个嵌套的foreach循环,该循环可以找到用户拥有的所有技能,但是我不确定这样做后如何确定他们是否拥有所有必需的技能。

var matches = new List<int>();

foreach (var employee in employeeSkills)
{
    foreach (var skills in skillsRequired)
    {
        if (employee.SKILL_ID == skills.SKILL_ID)
        {
            matches.Add(employee.SKILL_ID);
            matches.Add(skills.JOB_ID);
            matches.Add(employee.SKILL_ID);
        }
    }
}

“员工技能和技能要求”列表看起来像这样。

+--------------+--------+----------+
| EMP_SKILL_ID | EMP_ID | SKILL_ID |
+--------------+--------+----------+
|            1 |      1 |        1 |
|            2 |      1 |        2 |
|            3 |      1 |        3 |
|            4 |      2 |        1 |
|            5 |      2 |        2 |
|            6 |      2 |        4 |
+--------------+--------+----------+
+--------------+--------+----------+
| SKILL_REQ_ID | JOB_ID | SKILL_ID |
+--------------+--------+----------+
|            1 |      1 |        1 |
|            2 |      1 |        2 |
|            3 |      1 |        3 |
|            4 |      2 |        1 |
|            5 |      2 |        2 |
|            6 |      2 |        4 |
|            7 |      2 |        5 |
+--------------+--------+----------+

每个员工都需要正确的工作技能。 EMP_ID 1可以完成JOB_ID 1,但是没有人具备完成JOB_ID 2所需的全部技能。

是否有任何方法可以根据用户是否具有作业所需的全部或更多SKILL_ID来选择所有作业。

3 个答案:

答案 0 :(得分:1)

有很多方法可以做到这一点,这对于LINQ来说尤其容易。

例如,这将确保员工拥有skillsRequired列表中的所有技能:

skillsRequired.All(f => employeeSkills.Any(v => v.SKILL_ID == f.SKILL_ID));

或者,您可以检查员工是否缺少任何技能:

var requiredSkillIDs = skillsRequired.Select(f => f.SKILL_ID);
var employeeSkillIDs = employeeSkills.Select(f => f.SKILL_ID);
var missingSkillIDs = requiredSkillIDs.Except(employeeSkillsIDs);

这样,您可以通知用户缺少的技能。

强烈建议您看看docs on LINQ,它非常有用。

答案 1 :(得分:1)

以下是您问题的详细解决方案:

var matches = new Dictionary<int, List<int>>();

var employees = employeeSkills.ToLookup(emp => emp.EMP_ID, skill => skill.SKILL_ID);
var jobs = skillsRequired.GroupBy(skill => skill.JOB_ID, skill => skill.SKILL_ID);

foreach (var job in jobs)
{
    var capableEmployees = new List<int>();

    foreach (var employee in employees)
    {
        bool isCapable = true;

        foreach (int requiredSkill in job)
        {
            bool hasRequiredSkill = false;

            foreach (int skill in employee)
            {
                if (skill == requiredSkill)
                {
                    hasRequiredSkill = true;
                    break;
                }
            }

            if (!hasRequiredSkill)
            {
                isCapable = false;
                break;
            }
        }

        if (isCapable)
        {
            capableEmployees.Add(employee.Key);
        }
    }

    matches.Add(job.Key, capableEmployees);
}

一旦您了解了这一点并且知道了一些LINQ,就可以轻松地将其转换为:

var matches = new Dictionary<int, List<int>>();

var employees = employeeSkills.ToLookup(emp => emp.EMP_ID, skill => skill.SKILL_ID);
var jobs = skillsRequired.GroupBy(skill => skill.JOB_ID, skill => skill.SKILL_ID);

foreach (var job in jobs)
{
    var capableEmployees = (from employee in employees
                            where job.All(required => employee.Any(skill => skill == required))
                            select employee.Key).ToList();

    matches.Add(job.Key, capableEmployees);
}

甚至是这样:

var employees = employeeSkills.ToLookup(emp => emp.EMP_ID, skill => skill.SKILL_ID);
var matches = skillsRequired.GroupBy(skill => skill.JOB_ID, skill => skill.SKILL_ID)
                            .ToDictionary(job => job.Key,
                                          job => employees.Where(emp => job.All(required => emp.Any(skill => skill == required)))
                                                          .Select(emp => emp.Key).ToList());

这三个解决方案都是等效的,并且产生相同的结果。

请注意使用ToLookup方法对employeeSkills进行分组。 ToLookupGroupBy非常相似,只是它会立即进行评估。这意味着employeeSkills枚举仅被分组一次,而不是每个作业一次。

答案 2 :(得分:-1)

请尝试下面的代码,这些代码是不言自明的。我用字典使代码尽可能简单

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            List<EmployeeSkills> employeeSkills = new List<EmployeeSkills>() {
                new EmployeeSkills() { EMP_SKILL_ID = 1, EMP_ID = 1, SKILL_ID = 1},
                new EmployeeSkills() { EMP_SKILL_ID = 2, EMP_ID = 1, SKILL_ID = 2},
                new EmployeeSkills() { EMP_SKILL_ID = 3, EMP_ID = 1, SKILL_ID = 3},
                new EmployeeSkills() { EMP_SKILL_ID = 4, EMP_ID = 2, SKILL_ID = 1},
                new EmployeeSkills() { EMP_SKILL_ID = 5, EMP_ID = 2, SKILL_ID = 2},
                new EmployeeSkills() { EMP_SKILL_ID = 6, EMP_ID = 2, SKILL_ID = 4}
            };

            List<SkillsRequired> skillsRequired = new List<SkillsRequired>() {
                new SkillsRequired() { SKILL_REQ_ID = 1, JOB_ID = 1, SKILL_ID = 1},
                new SkillsRequired() { SKILL_REQ_ID = 2, JOB_ID = 1, SKILL_ID = 2},
                new SkillsRequired() { SKILL_REQ_ID = 3, JOB_ID = 1, SKILL_ID = 3},
                new SkillsRequired() { SKILL_REQ_ID = 4, JOB_ID = 2, SKILL_ID = 1},
                new SkillsRequired() { SKILL_REQ_ID = 5, JOB_ID = 2, SKILL_ID = 2},
                new SkillsRequired() { SKILL_REQ_ID = 6, JOB_ID = 2, SKILL_ID = 4},
                new SkillsRequired() { SKILL_REQ_ID = 7, JOB_ID = 2, SKILL_ID = 5}
            };

            var skills_employees = (from s in skillsRequired
                                    join e in employeeSkills on s.SKILL_ID equals e.SKILL_ID
                                    select new { skill_required_id = s.SKILL_REQ_ID, job_id = s.JOB_ID, skill_id = s.SKILL_ID, emp_skill_id = e.EMP_SKILL_ID, emp_id = e.EMP_ID }
                                    ).ToList();

            Dictionary<int, List<int>> job_skills = skillsRequired.GroupBy(x => x.JOB_ID, y => y.SKILL_ID)
                .ToDictionary(x => x.Key, y => y.ToList());

            var groups = skills_employees.GroupBy(x => new { employee = x.emp_id, job_id = x.job_id }).Select(x => new { employee = x.Key.employee, job_id = x.Key.job_id, skills = x.Select(y => y.skill_id).ToList() }).ToList();


            var results = groups.Select(x => new { employee_id = x.employee, job_id = x.job_id, qualifed = job_skills[x.job_id].All(y => x.skills.Contains(y)) ? "qualified" : "not qualified" }).ToList(); 


        }
    }
    public class EmployeeSkills
    {
        public int EMP_SKILL_ID { get; set; }
        public int EMP_ID { get; set; }
        public int SKILL_ID { get; set; }
    }
    public class SkillsRequired
    {
        public int SKILL_REQ_ID { get; set; }
        public int JOB_ID { get; set; }
        public int SKILL_ID { get; set; }
    }
}