这是我的第一篇文章,所以如果我在某些问题上失败,我会道歉,但我会尽量明确,以便你能跟着我。
我正在创建一个程序,检查合作伙伴(来自我工作的公司)是否拥有有效的法规(高级合作伙伴,认证合作伙伴和解决方案合作伙伴)。为了确认这一点,我检查他们的技术人员是否拥有有效的认证,并且认证合作伙伴和解决方案合作伙伴的一切正常。
因此,对于高级合作伙伴,我必须检查他们是否需要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
提前谢谢并保持良好的工作
好的,首先,道歉,我以前的回答显然是错的。您需要的是从不同数量的集合中生成笛卡尔积的方法。
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)));
Distinct
的重复ID。现在我们的条件只有在以下情况下才能满足:
if (distincStatues.Count() >= requiredDistinct.Length)
{
//condition met
}
一般解决方案(使用任意数量的约束)将通过回溯或不同的技术创建实际结果。
为每个必需的法规/证书分配技术人员,将约束检查为规则。
/// <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
输入。
您可以通过此查询进行第一次检查(所有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
,您可以让您的生活更轻松。