我有5个法规,我需要确保3个法规被3个不同的人占用

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

这是我的第一篇文章,所以如果我在某些问题上失败,我会道歉,但我会尽量明确,以便你能跟着我。

我正在创建一个程序,检查合作伙伴(来自我工作的公司)是否拥有有效的法规(高级合作伙伴,认证合作伙伴和解决方案合作伙伴)。为了确认这一点,我检查他们的技术人员是否拥有有效的认证,并且认证合作伙伴和解决方案合作伙伴的一切正常。

因此,对于高级合作伙伴,我必须检查他们是否需要5个法规但是3个人必须采用3个不同的法规。

因此,每个合作伙伴法规都有我创建的规则并且工作正常,因为它只检查这5个法规。所以对于Premiun合作伙伴,我需要在规则验证后做一些工作。

public async Task<bool> ValidateThirdPartyTypeRuleAsync(Partner partner, SpecializationExecutionThirdPartyType thirdPartyType)
{

    try
    {
        if (!string.IsNullOrEmpty(thirdPartyType.CRPValidationRule))
        {
            //Check if rule is valid
            using (var rule = new Evaluate(typeof(Partner), thirdPartyType.CRPValidationRule))
            {
                if (partner == null)
                {
                    throw new ArgumentNullException("Partner", "Partner cannot be null for ValidateThirdTypeRule execution");
                }

                //Run rule with partner
                var result = await rule.RunAsync(partner);

                if ((bool)result == true && partner.ThirdPartyType == "PPP")
                {
                    //Gets a list of technicians with valid satatutes for "PPP"
                    List<Technician> ValidTechnicianList = partner.Technicians.FindAll(s => 
                    s.StatutesHistory.Exists(a => (new int[] { 6, 11, 12, 8, 9 }).Contains(a.StatuteID) && a.Active)).ToList();

                    //Returns if partner is valid for the statute
                    if (ValidTechnicianList.Count() >= 3)
                    {
                            return true;
                    }
                    else
                    {
                        return false;
                    }
                }

                //Returns if partner is valid for his statute
                return (bool)result;
            }
      }
  }

因此,您可以想象,这个“Count> = 3”不能完成这项工作,因为如果1名技术人员需要认证,而另外2名技术人员只有一名,那么它将返回“True”。

这是高级合作伙伴的规则:

Technicians.Where(a => a.StatutesHistory.Exists(b => new int[] {6, 11}.Contains(b.StatuteID) && b.Active == true)).Count() >= 1 && 
Technicians.Where(a => a.StatutesHistory.Exists(b => new int[] {12}.Contains(b.StatuteID) && b.Active == true)).Count() >= 1 &&  
Technicians.Where(a => a.StatutesHistory.Exists(b => new int[] {8}.Contains(b.StatuteID) && b.Active == true)).Count() >= 1 &&  
Technicians.Where(a => a.StatutesHistory.Exists(b => new int[] {9, 25}.Contains(b.StatuteID) && b.Active == true)).Count() >= 1 &&  
Technicians.Where(a => a.StatutesHistory.Exists(b => new int[] {5, 26}.Contains(b.StatuteID) && b.Active == true)).Count() >= 1

提前谢谢并保持良好的工作

c# linq
3个回答
1
投票

好的,首先,道歉,我以前的回答显然是错的。您需要的是从不同数量的集合中生成笛卡尔积的方法。

Eric Lippert有一篇关于这个主题的精彩文章,你可以在下面的文章中找到一个非常优雅的解决方案:Computing a Cartesian Product with LINQ

//Eric Lippert's implementation
static IEnumerable<IEnumerable<T>> CartesianProduct<T>(this 
    IEnumerable<IEnumerable<T>> sequences)
{
    var emptyProduct =
        new[] { Enumerable.Empty<T>() };

    return sequences.Aggregate(
      emptyProduct,
      (accumulator, sequence) =>
        from accseq in accumulator
        from item in sequence
        select accseq.Concat(new[] { item }));
}

而现在,您的问题很容易解决:

 var requiredDistinct = new[] { 6, 11, 12 };
 var distinctStatutes = 
    technicians.Select(t => t.StatuteIds)
               .CartesianProduct()
               .Select(p => p.Distinct())
               .Where(p => requiredDistinct.All(
                  requiredId => p.Contains(requiredId)));
  1. 我们计算所有法定ID的笛卡尔积。
  2. 我们过滤掉每个产品上调用Distinct的重复ID。
  3. 然后我们过滤掉那些并非所有必需法规都存在的产品。

现在我们的条件只有在以下情况下才能满足:

if (distincStatues.Count() >= requiredDistinct.Length)
{ 
    //condition met
}

0
投票

一般解决方案(使用任意数量的约束)将通过回溯或不同的技术创建实际结果。

为每个必需的法规/证书分配技术人员,将约束检查为规则。

/// <summary>
/// recursive solution (backtracking)
/// </summary>
/// <param name="Technicians">All technicians (possibly pre-filtered so they have at least one relevant certificate)</param>
/// <param name="DistinctSlots">The resulting statute assignment. The input needs to satisfy correctnessRule(DistinctSlots)</param>
/// <param name="ProcessingSet">The statute IDs to be assigned according to the rules</param>
/// <param name="completenessRule">A predicate that checks the completeness of a result. It will be applied when a possible solution is fully assigned</param>
/// <param name="correctnessRule">A predicate that checks the correctness of an assignment. It needs to be true even for valid sub-results where some statutes are not assigned</param>
/// <returns>True if DistinctSlots contains a solution</returns>
private static bool FillSlots(List<Technician> Technicians, Dictionary<int, Technician> DistinctSlots, IEnumerable<int> ProcessingSet, Predicate<Dictionary<int, Technician>> completenessRule, Predicate<Dictionary<int, Technician>> correctnessRule)
{
    if (!ProcessingSet.Any())
    {
        return completenessRule(DistinctSlots);
    }
    var key = ProcessingSet.First();
    var nextSet = ProcessingSet.Skip(1);
    foreach (var tech in Technicians.Where(x => x.StatutesHistory.Any(y => y.StatuteID == key)))
    {
        DistinctSlots[key] = tech;
        if (correctnessRule(DistinctSlots) &&
            FillSlots(Technicians, DistinctSlots, nextSet, completenessRule, correctnessRule))
        {
            return true;
        }
    }
    DistinctSlots.Remove(key);
    return false;
}

完整的结果必须满足completenessRule,可以实现为

private static int[] StatuteIDs = new int[] { 6, 11, 12, 8, 9 };
private static bool CompletenessRule(Dictionary<int, Technician> assignment)
{
    // ensure all statuteIDs are available as keys in the dictionary and all values are not-null
    return !StatuteIDs.Except(assignment.Keys).Any() &&
        assignment.Values.All(x => x != null);
}

正确的结果必须满足正确性规则。此示例规则允许技术人员拥有多个法规(9,12,......),但是法规6,8和11需要不同的技术人员:

private static bool CorrectnessRule(Dictionary<int, Technician> assignment)
{
    return
        CompareNullOrDifferent(assignment, 6, 8) &&
        CompareNullOrDifferent(assignment, 6, 11) &&
        CompareNullOrDifferent(assignment, 8, 11);
}
private static bool CompareNullOrDifferent(Dictionary<int, Technician> assignment, int key1, int key2)
{
    Technician t1, t2;
    return
        !assignment.TryGetValue(key1, out t1) ||
        !assignment.TryGetValue(key2, out t2) ||
        t1 != t2;
}

按如下方式执行求解器:

Dictionary<int, Technician> DistinctSlots = new Dictionary<int, Technician>();

bool foundResult = false;
foundResult = FillSlots(Technicians, DistinctSlots, StatuteIDs, CompletenessRule, CorrectnessRule);

if (!foundResult)
{
    Console.WriteLine("Not enough different technicians");
}
else
{
    Console.WriteLine("Enough different technicians");
}

用一些List<Technician> Technicians输入。


0
投票

您可以通过此查询进行第一次检查(所有5种状态):

var hasAllRequired = !(new int[] { 6, 11, 12, 8, 9 }
    .Except(partner.Technicians
        .SelectMany(t => StatutesHistory.Select(h => h.StatuteID))).Any());

并通过此查询进行第二次检查:

var pass3Check = partner.Technicians
    .Select(t => t.StatutesHistory.Select(h => h.StatuteID).Distinct().Count())
    .Count(statusCount => statusCount >= 3) >= 3;

最后一个查询首先创建每个技术人员(直到Count())的部分)的不同状态计数列表,然后检查其中至少有3个计数为3或更多。

顺便说一下,通过为您的状态值引入enum,您可以让您的生活更轻松。

热门问题
推荐问题
最新问题