具有相等组的双重随机分配

时间:2014-05-28 15:56:49

标签: vb.net algorithm random random-sample

我正在尝试为我正在处理的网站构建一个随机样本和随机分配生成器,该网站应该将相同数量的随机选择项分配给一组变量人。

例如:

在本轮评估中,我们有9名评估员,477项需要由两名评估员评分(同一评估员未对同一项目评分两次)。这将需要进行954次“评估”,每位评估员需要106次。

因此我需要一个像......这样的最终清单。

(Item, Assessor1, Assessor2)
(1, A, B)
(2, C, D)
(3, E, F)
(4, G, H)
(5, H, B)
(6, B, F)
.
.
.
And so on

我发现可以进行随机数生成的网站,甚至可以对群组进行随机分配的网站,但即便如此,我仍然会发现同一评估者将在整个结果中对同一项进行评分的情况。

我不太关心固有的随机性,更关心的是确保每个结果列表让每个评估者对相同数量的项目进行评分而不对同一项目进行评分。

我通常可以得到它 - 关闭 - 并且可能一个等级将是1或2个,而另一个将少1或2个,但不幸的是,它们是相同分组的硬性要求。 / p>

修改

实施@ Tinstaafl的代码并执行以下操作:

  Dim col As New MyItemCollection

    col.AddAssessor("A")
    col.AddAssessor("B")
    col.AddAssessor("C")
    col.AddAssessor("D")
    col.AddAssessor("E")
    col.AddAssessor("F")
    col.AddAssessor("G")
    col.AddAssessor("H")
    col.AddAssessor("I")

    For I As Integer = 1 To 477
        col.AddItem(I.ToString)
    Next

    Dim newList As List(Of MyItemCollection.MyItem) = col.AssignAssessors

    For Each item As MyItemCollection.MyItem In col.itemlist
        Response.Write(item.ToString & "<br/>")
    Next

不幸的是我的输出看起来像

1 - F - F
2 - I - I
3 - E - E
4 - F - F
5 - C - C
6 - D - D
7 - G - G
8 - A - A
9 - C - C
10 - B - B
11 - D - D
12 - D - D
13 - D - D
14 - D - D
15 - H - H

等等......

3 个答案:

答案 0 :(得分:0)

我能想到的一个想法如下:

对评估员进行洗牌{1-9}。然后根据此shuffle的结果顺序将前4.5个项目分配给它们。

然后再次洗牌。再次按顺序将它们分配给下一个项目。如果第一个评估者恰好是已经分配给第5个项目的评估者,那么在列表中交换第一个和第二个评估者。

继续为所有项目执行此操作。

答案 1 :(得分:0)

一种方法是使用集合类和项目和评估者的嵌入类。这是一个部分实现,用于说明如何生成列表:

Public Class MyItemCollection
    Class Assessor
        Public Name As String = ""
        Public Shared Operator <>(LH As Assessor, RH As Assessor) As Boolean
            Return LH.Name <> RH.Name
        End Operator
        Public Shared Operator =(LH As Assessor, RH As Assessor) As Boolean
            Return RH.Name = LH.Name
        End Operator
        Public Overrides Function ToString() As String
            Return Name
        End Function
    End Class
    Class MyItem
        Public Name As String = ""
        Public Assessor1 As New Assessor
        Public Assessor2 As New Assessor
        Public Overrides Function ToString() As String
            Return Name & " - " & Assessor1.ToString & " - " & Assessor2.ToString
        End Function
    End Class
    Private AssessorList As New List(Of Assessor)
    Private ItemList As New List(Of MyItem)
    Public Sub AddAssessor(Name As String)
        AssessorList.Add(New Assessor With {.Name = Name})
    End Sub
    Public Sub AddItem(Name As String)
        ItemList.Add(New MyItem With {.Name = Name})
    End Sub
    Private Rnd As New Random(Now.Millisecond * Now.Day * Now.Minute)
    Public Function AssignAssessors() As List(Of MyItem)
        Dim OutVal As New List(Of MyItem)
        Dim average As Integer = ((ItemList.Count \ AssessorList.Count) * 2) + 5
        Dim AssessorCount(AssessorList.Count - 1) As Integer
        For Each item As MyItem In ItemList
            Dim firstassessorindex As Integer
            Do
                firstassessorindex = Rnd.Next(0, AssessorList.Count)

            Loop Until AssessorCount(firstassessorindex) <= average
            item.Assessor1 = AssessorList(firstassessorindex)
            AssessorCount(firstassessorindex) += 1
            Dim secondassessorindex As Integer
            Do
                secondassessorindex = Rnd.Next(0, AssessorList.Count)

            Loop Until AssessorList(secondassessorindex) <> item.Assessor1 AndAlso AssessorCount(secondassessorindex) < average
            item.Assessor2 = AssessorList(secondassessorindex)
            AssessorCount(secondassessorindex) += 1
        Next
        OutVal = ItemList
        Return OutVal
    End Function
End Class

你的解释中有一点不清楚的是,Assessor1和Assessor2之间的分配是否重要(如果评估员是第二次评估员的次数比第一次评估者多吗?)。如果需要,那么AssessorCount可能需要List(Of Tuple(Integer,Integer))而不是List(Of Integer)

返回列表中每个项目的ToString方法格式为 -

ItemName - Assessor1Name - Assessor2Name

答案 2 :(得分:0)

我不确定我是否理解你的作业规则,但这可能很接近。

var assessors = new []
{
    "A", "B", "C",
    "D", "E", "F",
    "G", "H", "I",
};

var rnd = new Random();

var query =
    from a1 in assessors
    from a2 in assessors
    where a1 != a2
    orderby rnd.Next()
    select new { a1, a2};

var results =
    Enumerable
        .Range(1, 477)
        .Zip(query
            .Repeat(),
            (i, aa) => new
            {
                Item = i,
                Assessor1 = aa.a1,
                Assessor2 = aa.a2,
            });

我得到了这样的结果:

  1  F  B
  2  E  C
  3  D  H
    ... 
476  F  C
477  B  E