Random selection with a caveat / criteria

2

I have a 6 x 6 grid. I have 36 samples split into three equal groups (A, B, and C).

I want a formula to arrange the samples in that grid randomly. However each row and each column must contain two of each group. Doing this manually once or twice is easy, but there are a massive number of combinations.

I am open in terms of software choices so long as it is freeware or Microsoft Office based.

Thank you!

Andrew Cooke

Posted 2015-05-20T13:02:56.540

Reputation: 21

Welcome to SuperUser! Interesting question. To clarify, does it matter if the members of a given group are always in the same place in the grid? That is, is it an acceptable solution if the first row is always AABBCC, even if all twelve A samples can be swapped through those first two spots? – hBy2Py – 2015-05-20T13:59:20.427

Brian Unfortunately not. Imagine each grid coordinate is considered a "slot" and there are twelve slots for each sample and two of each sample in each row and column. It is the location of these slots I want randomised (within my caveat of 2 in each row and column). Think of it like a 6 x 6 sudoku. There are millions of combinations that work, I essentially want a method that uses randomness to create one of those millions of combinations.

One thought was make a grid manually that works. Then randomly swap the location of entire columns, then do the same with rows - woul that work? – Andrew Cooke – 2015-05-21T12:47:16.233

<nod>, was afraid that's what you were after. The random swapping might work - I don't know enough about algorithms and the math of this sort of thing to know if it would provide access to the entire space of possible configurations, though. If you don't need to ensure such exhaustive performance, it might work well enough. You probably would need to code it in VBA, as writing worksheet formulas to handle the row/column swaps would be tricky. I'll chew on it, though. – hBy2Py – 2015-05-21T13:48:04.380

Answers

1

I put together a tool for generating random row/column permutations with a couple of formulas and some VBA. The sheet layout looks like this:

Excel snip

The reference grid is a trivial example of a valid matrix, as posted in Gary's Student's preliminary answer (possibly since deleted). The row and column permutations incorporate all possible unique combinations of permutations for the 6x6 grid. (This could easily be modified to include non-unique permutations, if desired.) The values in E12:E26 and L12:L26 are randomly seeded to either zero or one, to provide the basis for whether or not to perform a given permutation. Columns D and K just convert these to boolean values for simplified handling within the VBA (see below). The permuted grid is generated by the custom function doSwap, entered as an array formula. Pressing F9 to trigger sheet recalculation causes the various RAND functions to re-generate their random values, changing the series of permutations to be performed.

The VBA code that enables this behavior is:

Function doSwap(srcRg As Range, rowSwaps As Range, colSwaps As Range) As Variant
    Dim workVt As Variant
    Dim iter As Long

    workVt = srcRg.Value

    ' Do row swaps
    For iter = 1 To rowSwaps.Rows.Count
        With rowSwaps
            If .Cells(iter, 3).Value Then
                workVt = swapRow(workVt, .Cells(iter, 1), .Cells(iter, 2))
            End If
        End With
    Next iter

    ' Do col swaps
    For iter = 1 To colSwaps.Rows.Count
        With colSwaps
            If .Cells(iter, 3).Value Then
                workVt = swapCol(workVt, .Cells(iter, 1), .Cells(iter, 2))
            End If
        End With
    Next iter

    ' Store and return
    doSwap = workVt

End Function

Function swapCol(ByVal inArr As Variant, idx1 As Long, idx2 As Long) As Variant
    Dim tempVal As Variant, workVt As Variant
    Dim iter As Long

    ' Check if Range or Array input
    If IsObject(inArr) Then
        If TypeOf inArr Is Range Then
            workVt = inArr.Value
        Else
            swapCol = "ERROR"
            Exit Function
        End If
    Else
        workVt = inArr
    End If

    ' Just crash if not correct size
    ' Do swap
    For iter = LBound(workVt, 1) To UBound(workVt, 1)
        tempVal = workVt(iter, idx1)
        workVt(iter, idx1) = workVt(iter, idx2)
        workVt(iter, idx2) = tempVal
    Next iter

    ' Return
    swapCol = workVt

End Function

Function swapRow(ByVal inArr As Variant, idx1 As Long, idx2 As Long) As Variant
   Dim tempVal As Variant, workVt As Variant
   Dim iter As Long

    ' Check if Range or Array input
    If IsObject(inArr) Then
        If TypeOf inArr Is Range Then
            workVt = inArr.Value
        Else
            swapRow = "ERROR"
            Exit Function
        End If
    Else
        workVt = inArr
    End If

    ' Just crash if not correct size
    ' Do swap
    For iter = LBound(workVt, 2) To UBound(workVt, 2)
        tempVal = workVt(idx1, iter)
        workVt(idx1, iter) = workVt(idx2, iter)
        workVt(idx2, iter) = tempVal
    Next iter

    ' Return
    swapRow = workVt

End Function

The above code is not well robustified, but serves the present purpose. Extension/generalization should be pretty straightforward, if needed. In particular, it should handle as-is any size of 2-D reference grid, even one that is non-square. The key thing is to ensure the arrays of permutation instructions are set up properly.

EDIT: After playing with it a bit, it's clear this solution doesn't provide access to the full space of possible permutations. So, I tweaked it by adding a random "bit-shift" to swap the type labels among themselves. To simplify things, I switched from ABC labels to 123 labels, which allows implementation by a simple MOD operation, and also a quick-glance sanity check in the form of row and column sums:

Excel snip

hBy2Py

Posted 2015-05-20T13:02:56.540

Reputation: 2 123

Good job Brian! It appears to work very well! – Gary's Student – 2015-05-21T20:15:06.987

Wow. From my initial look at this it looks absolutely ideal. I'll take some town now to have a more in depth try at using this. Can't thank you enough for the effort! – Andrew Cooke – 2015-05-24T12:16:21.190

Sure! Happy to help. If it works well for you, the only thanks needed is an accepted answer. :-) – hBy2Py – 2015-05-25T03:53:30.140

0

There is a very simple way to accomplish this. First pre-assign slots to each of the three types:

enter image description here

Then take the first sample, for example SAMPLE_A_1, and place it randomly in one of the A-slots. Then continue to process each of the remaining 35 samples.


If this approach is acceptable, I'll post a short program to populate the matrix. If the approach is not acceptable, I will delete this post.

Gary's Student

Posted 2015-05-20T13:02:56.540

Reputation: 15 540

Hi - Apologies there was some ambiguity in my original question. All samples of A are identical as are those of B and C. So the problem is to do with the "slots" (as you used them). The formation of the "slots" must be random, but within the caveat (2 of each sample in each rown and column).

One way I've looked at, and would like feedback on was: I made a grid just like you showed above. I then randomly arranged those columns and then rows. I'm just not sure if that is random or would that method not allow for every possibility.

Thanks for getting back to me! – Andrew Cooke – 2015-05-21T12:40:55.453

@AndrewCooke....Perhaps we can start with a known template and "shuffle the cards".......if we start from my template and simply interchange columns A and B, we end up with a valid template.....in fact, we can interchange ANY two randomly selected columns and have a valid template............the same is true for rows...this may be a way of generating cases. – Gary's Student – 2015-05-21T12:55:51.327