Loading

多条件试卷提取的问题(附带测试代码)

问题来自http://q.cnblogs.com/q/38789/

题目如下:

最近在开发一个项目,做一个试题系统,其中有一个组卷功能(随机抽题),试题属性有:所属专业、题型、难易度、认知层次等。 现在需要实现随机组卷,抽出100道题满足以下条件:

条件1:

所属专业: 内科 20%  外科 30%    口腔科 25%  神经科 25。

条件2:

题型: 单选题  30%  多选题 40%   简答题 30%

条件3:

难易度:  难 20%   中 60%    易 20% 

条件4:

认知层次: 记忆25%   应用40%   理解 35%

这类题在博问看到了好几次,花了点时间写了下面的代码希望能帮助到需要的人。

 

其实多条件问题之所以难就是在效率上,所以一般是反过来解决,看条件挑符合的,测试中因为是随机生成的样本库,随机了几次都打不到100题,所以直接生成相应的题目。

下面类实现了两种场景的效率考虑,如果是遍历比较快的可以直接调用AddTest全加一遍,如果是查询比较快的可以通过KindOfTestNeed来提取查询条件,目前的代码生成的结果每次是一样的,如果有真实的库可以采取查询结果的随机化和KindOfTestNeed条件的随机化来生成不同的卷子。

实际引用可以参考Artwl的文章:

 

实例讲解遗传算法——基于遗传算法的自动组卷系统【理论篇】

 

实例讲解遗传算法——基于遗传算法的自动组卷系统【实践篇】

直接上代码:

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
    {
        SingleAnswer,
        MultiAnswer,
        ShortAnswer
    }
    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);

            myTest.AddMajorCondition(Major.Medicine, 0.2);
            myTest.AddMajorCondition(Major.Surgery, 0.3);
            myTest.AddMajorCondition(Major.Stomatology, 0.25);
            myTest.AddMajorCondition(Major.Neurology, 0.25);

            myTest.AddTestTypeCondidtion(TestType.SingleAnswer, 0.3);
            myTest.AddTestTypeCondidtion(TestType.MultiAnswer, 0.4);
            myTest.AddTestTypeCondidtion(TestType.ShortAnswer, 0.3);

            myTest.AddDifficultyCondition(Difficulty.Hard, 0.2);
            myTest.AddDifficultyCondition(Difficulty.Middle, 0.6);
            myTest.AddDifficultyCondition(Difficulty.Easy, 0.2);

            myTest.AddAwarenessCondition(Awareness.Remember, 0.25);
            myTest.AddAwarenessCondition(Awareness.Impl, 0.4);
            myTest.AddAwarenessCondition(Awareness.Understand, 0.35);

            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!");
                }
                if (!myTest.AddTest(item))
                {
                    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 long _total;
        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)
        {
            _majorConditions.Add(major, new ConditionStats(scale));
        }

        public void AddTestTypeCondidtion(TestType testType, double scale)
        {
            _testTypeConditions.Add(testType, new ConditionStats(scale));
        }

        public void AddDifficultyCondition(Difficulty difficulty, double scale)
        {
            _difficultyConditions.Add(difficulty, new ConditionStats(scale));
        }

        public void AddAwarenessCondition(Awareness awareness, double scale)
        {
            _awarenessConditions.Add(awareness, new ConditionStats(scale));
        }

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

        public bool AddTest(ExerciseItem item)
        {
            _exerciseItems.Add(item);
            UpdateStats(item);
            if (IsTooMuch())
            {
                _exerciseItems.Remove(item);
                UpdateStats(item);
                return false;
            }
            return true;
        }

        private int i = 1;
        public void UpdateStats(ExerciseItem exerciseItem)
        {
            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
1    Medicine    SingleAnswer    Hard    Remember
2    Medicine    SingleAnswer    Hard    Remember
3    Medicine    SingleAnswer    Hard    Remember
4    Medicine    SingleAnswer    Hard    Remember
5    Medicine    SingleAnswer    Hard    Remember
6    Medicine    SingleAnswer    Hard    Remember
7    Medicine    SingleAnswer    Hard    Remember
8    Medicine    SingleAnswer    Hard    Remember
9    Medicine    SingleAnswer    Hard    Remember
10    Medicine    SingleAnswer    Hard    Remember
11    Medicine    SingleAnswer    Hard    Remember
12    Medicine    SingleAnswer    Hard    Remember
13    Medicine    SingleAnswer    Hard    Remember
14    Medicine    SingleAnswer    Hard    Remember
15    Medicine    SingleAnswer    Hard    Remember
16    Medicine    SingleAnswer    Hard    Remember
17    Medicine    SingleAnswer    Hard    Remember
18    Medicine    SingleAnswer    Hard    Remember
19    Medicine    SingleAnswer    Hard    Remember
20    Medicine    SingleAnswer    Hard    Remember
22    Surgery    SingleAnswer    Middle    Remember
23    Surgery    SingleAnswer    Middle    Remember
24    Surgery    SingleAnswer    Middle    Remember
25    Surgery    SingleAnswer    Middle    Remember
26    Surgery    SingleAnswer    Middle    Remember
28    Surgery    SingleAnswer    Middle    Impl
29    Surgery    SingleAnswer    Middle    Impl
30    Surgery    SingleAnswer    Middle    Impl
31    Surgery    SingleAnswer    Middle    Impl
32    Surgery    SingleAnswer    Middle    Impl
34    Surgery    MultiAnswer    Middle    Impl
35    Surgery    MultiAnswer    Middle    Impl
36    Surgery    MultiAnswer    Middle    Impl
37    Surgery    MultiAnswer    Middle    Impl
38    Surgery    MultiAnswer    Middle    Impl
39    Surgery    MultiAnswer    Middle    Impl
40    Surgery    MultiAnswer    Middle    Impl
41    Surgery    MultiAnswer    Middle    Impl
42    Surgery    MultiAnswer    Middle    Impl
43    Surgery    MultiAnswer    Middle    Impl
44    Surgery    MultiAnswer    Middle    Impl
45    Surgery    MultiAnswer    Middle    Impl
46    Surgery    MultiAnswer    Middle    Impl
47    Surgery    MultiAnswer    Middle    Impl
48    Surgery    MultiAnswer    Middle    Impl
49    Surgery    MultiAnswer    Middle    Impl
50    Surgery    MultiAnswer    Middle    Impl
51    Surgery    MultiAnswer    Middle    Impl
52    Surgery    MultiAnswer    Middle    Impl
53    Surgery    MultiAnswer    Middle    Impl
55    Stomatology    MultiAnswer    Middle    Impl
56    Stomatology    MultiAnswer    Middle    Impl
57    Stomatology    MultiAnswer    Middle    Impl
58    Stomatology    MultiAnswer    Middle    Impl
59    Stomatology    MultiAnswer    Middle    Impl
60    Stomatology    MultiAnswer    Middle    Impl
61    Stomatology    MultiAnswer    Middle    Impl
62    Stomatology    MultiAnswer    Middle    Impl
63    Stomatology    MultiAnswer    Middle    Impl
64    Stomatology    MultiAnswer    Middle    Impl
65    Stomatology    MultiAnswer    Middle    Impl
66    Stomatology    MultiAnswer    Middle    Impl
67    Stomatology    MultiAnswer    Middle    Impl
68    Stomatology    MultiAnswer    Middle    Impl
69    Stomatology    MultiAnswer    Middle    Impl
71    Stomatology    MultiAnswer    Middle    Understand
72    Stomatology    MultiAnswer    Middle    Understand
73    Stomatology    MultiAnswer    Middle    Understand
74    Stomatology    MultiAnswer    Middle    Understand
75    Stomatology    MultiAnswer    Middle    Understand
77    Stomatology    ShortAnswer    Middle    Understand
78    Stomatology    ShortAnswer    Middle    Understand
79    Stomatology    ShortAnswer    Middle    Understand
80    Stomatology    ShortAnswer    Middle    Understand
81    Stomatology    ShortAnswer    Middle    Understand
83    Neurology    ShortAnswer    Middle    Understand
84    Neurology    ShortAnswer    Middle    Understand
85    Neurology    ShortAnswer    Middle    Understand
86    Neurology    ShortAnswer    Middle    Understand
87    Neurology    ShortAnswer    Middle    Understand
89    Neurology    ShortAnswer    Easy    Understand
90    Neurology    ShortAnswer    Easy    Understand
91    Neurology    ShortAnswer    Easy    Understand
92    Neurology    ShortAnswer    Easy    Understand
93    Neurology    ShortAnswer    Easy    Understand
94    Neurology    ShortAnswer    Easy    Understand
95    Neurology    ShortAnswer    Easy    Understand
96    Neurology    ShortAnswer    Easy    Understand
97    Neurology    ShortAnswer    Easy    Understand
98    Neurology    ShortAnswer    Easy    Understand
99    Neurology    ShortAnswer    Easy    Understand
100    Neurology    ShortAnswer    Easy    Understand
101    Neurology    ShortAnswer    Easy    Understand
102    Neurology    ShortAnswer    Easy    Understand
103    Neurology    ShortAnswer    Easy    Understand
104    Neurology    ShortAnswer    Easy    Understand
105    Neurology    ShortAnswer    Easy    Understand
106    Neurology    ShortAnswer    Easy    Understand
107    Neurology    ShortAnswer    Easy    Understand
108    Neurology    ShortAnswer    Easy    Understand

 

posted @ 2012-07-18 14:11  today4king  阅读(490)  评论(1编辑  收藏  举报