# 多条件试卷提取的问题（附带测试代码）

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using FizzWare.NBuilder;
using Xunit;

namespace ExerciseGenerateSystem
{
//条件1：
//所属专业: 内科 20%  外科 30%    口腔科 25%  神经科 25。
//条件2：
//题型: 单选题  30%  多选题 40%   简答题 30%
//条件3：
//难易度：  难 20%   中 60%    易 20%
//条件4：
//认知层次： 记忆25%   应用40%   理解 35%
public class ExerciseItem
{
public long Id { get; set; }
public Major Major { get; set; }
public TestType TestType { get; set; }
public Difficulty Difficulty { get; set; }
public Awareness Awareness { get; set; }

public override string ToString()
{
return string.Format("{0}\t{1}\t{2}\t{3}\t{4}", this.Id, this.Major, this.TestType, this.Difficulty,
this.Awareness);
}
}
public enum Major
{
[Description("内科")]
Medicine,
[Description("外科")]
Surgery,
[Description("口腔科")]
Stomatology,
[Description("神经科")]
Neurology
}
public enum TestType
{
}
public enum Difficulty
{
Hard,
Middle,
Easy
}
public enum Awareness
{
Remember,
Impl,
Understand
}

public class GenerateMyTest
{
private const int TestTotal = 100;
[Fact]
public void DoGenerate()
{
//var testLibary = Builder<ExerciseItem>
//    .CreateListOfSize(299999)
//    .All()
//    .With(e=>e.Awareness=(Awareness)random(2))
//    .With(e => e.Difficulty = (Difficulty)random(2))
//    .With(e => e.Major = (Major)random(3))
//    .With(e => e.TestType = (TestType)random(2))
//    .Build();
var myTest = new MyTest(TestTotal);

var kindOfTestNeed = myTest.KindOfTestNeed();

for (var i = 1l; !myTest.IsValid() && kindOfTestNeed != null; i++)
{
var item = new ExerciseItem
{
Id = i,
Awareness = kindOfTestNeed.Item4,
Difficulty = kindOfTestNeed.Item3,
Major = kindOfTestNeed.Item1,
TestType = kindOfTestNeed.Item2
};
//testLibary.FirstOrDefault(
//    t =>
//    !myTest.Contains(t)
//    && t.Major == kindOfTestNeed.Item1
//    && t.Difficulty == kindOfTestNeed.Item3
//    && t.TestType == kindOfTestNeed.Item2
//    && t.Awareness == kindOfTestNeed.Item4);
if (item == null)
{
myTest.Print();
throw new Exception("Libary is not fit this conditions!");
}
{
kindOfTestNeed = myTest.KindOfTestNeed();
}
}
myTest.Print();
Assert.True(myTest.Validate());

}
Random r = new Random();
private int random(int max)
{
return r.Next(0, max);
}
[Fact]
public void Test()
{
Console.WriteLine(123d / 123);
}
}

public class ConditionStats
{
public ConditionStats(double scale)
{
this.Scale = scale;
}
public double Scale;

public bool IsEnough { get; set; }

public bool IsTooMuch { get; set; }

public void Update(long count, long total)
{
var ret = (double)count / (double)total;
IsEnough = ret >= Scale;
IsTooMuch = ret > Scale;
}
}

public class MyTest
{
private readonly IList<ExerciseItem> _exerciseItems = new List<ExerciseItem>();
private readonly Dictionary<Major, ConditionStats> _majorConditions = new Dictionary<Major, ConditionStats>();
private readonly Dictionary<TestType, ConditionStats> _testTypeConditions = new Dictionary<TestType, ConditionStats>();
private readonly Dictionary<Difficulty, ConditionStats> _difficultyConditions = new Dictionary<Difficulty, ConditionStats>();
private readonly Dictionary<Awareness, ConditionStats> _awarenessConditions = new Dictionary<Awareness, ConditionStats>();

public MyTest(long total)
{
_total = total;
}

public void AddMajorCondition(Major major, double scale)
{
}

public void AddTestTypeCondidtion(TestType testType, double scale)
{
}

public void AddDifficultyCondition(Difficulty difficulty, double scale)
{
}

public void AddAwarenessCondition(Awareness awareness, double scale)
{
}

public bool Contains(ExerciseItem item)
{
return _exerciseItems.Any(e => e.Id == item.Id);
}

{
if (IsTooMuch())
{
_exerciseItems.Remove(item);
return false;
}
return true;
}

private int i = 1;
{
i++;
var major = _majorConditions[exerciseItem.Major];
major.Update(_exerciseItems.LongCount(e => e.Major == exerciseItem.Major), _total);
var testType = _testTypeConditions[exerciseItem.TestType];
testType.Update(_exerciseItems.LongCount(e => e.TestType == exerciseItem.TestType), _total);
var difficulty = _difficultyConditions[exerciseItem.Difficulty];
difficulty.Update(_exerciseItems.LongCount(e => e.Difficulty == exerciseItem.Difficulty), _total);
var awareness = _awarenessConditions[exerciseItem.Awareness];
awareness.Update(_exerciseItems.LongCount(e => e.Awareness == exerciseItem.Awareness), _total);
}

public bool IsTooMuch()
{
return _majorConditions.Any(mc => mc.Value.IsTooMuch)
||
_testTypeConditions.Any(mc => mc.Value.IsTooMuch)
||
_difficultyConditions.Any(mc => mc.Value.IsTooMuch)
||
_awarenessConditions.Any(mc => mc.Value.IsTooMuch);
}

public Tuple<Major, TestType, Difficulty, Awareness> KindOfTestNeed()
{
if (_majorConditions.Any(mc => !mc.Value.IsEnough)
&&
_testTypeConditions.Any(mc => !mc.Value.IsEnough)
&&
_difficultyConditions.Any(mc => !mc.Value.IsEnough)
&&
_awarenessConditions.Any(mc => !mc.Value.IsEnough))
{
return new Tuple<Major, TestType, Difficulty, Awareness>
(
_majorConditions.First(mc => !mc.Value.IsEnough).Key,
_testTypeConditions.First(mc => !mc.Value.IsEnough).Key,
_difficultyConditions.First(mc => !mc.Value.IsEnough).Key,
_awarenessConditions.First(mc => !mc.Value.IsEnough).Key
)
;
}
return null;
}
public bool Validate()
{
return _majorConditions.All(mc => mc.Value.IsEnough)
&&
_testTypeConditions.All(mc => mc.Value.IsEnough)
&&
_difficultyConditions.All(mc => mc.Value.IsEnough)
&&
_awarenessConditions.All(mc => mc.Value.IsEnough);
}
public bool IsValid()
{
return _total == _exerciseItems.LongCount();
}

public void Print()
{
Console.WriteLine("Totoal:{0}", _exerciseItems.Count());
_exerciseItems.ToList().ForEach(Console.WriteLine);
}
}
}


测试结果：

DoGenerate : PassedTotoal:100