Я собрал инструмент для генерации случайных перестановок строк / столбцов с помощью нескольких формул и некоторого VBA. Макет листа выглядит следующим образом:
Сетка ссылок - это тривиальный пример действительной матрицы, опубликованной в предварительном ответе ученика Гэри (возможно, с тех пор, как он был удален). Перестановки строк и столбцов включают в себя все возможные уникальные комбинации перестановок для сетки 6x6. (Это можно легко изменить, чтобы включить неуникальные перестановки, если это необходимо.) Значения E12:E26
и L12:L26
случайным образом добавляются в ноль или единицу, чтобы обеспечить основу для того, выполнять или нет заданную перестановку. Столбцы D
и K
просто преобразуйте их в логические значения для упрощенной обработки в VBA (см. Ниже). Переставленная сетка генерируется пользовательской функцией doSwap
, вводимой в виде формулы массива. НажатиеF9
для запуска пересчета листа вызывает различныеRAND
функции для генерации их случайных значений, изменения серии перестановок, которые будут выполнены.
Код VBA, который включает это поведение:
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
Вышеприведенный код не очень хорошо оправдан, но служит настоящей цели. Расширение / обобщение должно быть довольно простым, если это необходимо. В частности, он должен обрабатывать как-бы любой размер двумерной эталонной сетки, даже не квадратный. Ключевым моментом является обеспечение правильной настройки массивов команд перестановки.
РЕДАКТИРОВАТЬ: немного поиграв, становится ясно, что это решение не предоставляет доступ ко всему пространству возможных перестановок. Итак, я изменил его, добавив случайный « сдвиг битов », чтобы поменять метки типов между собой. Для упрощения я переключился с ABC
меток на 123
метки, что позволяет реализовать простую MOD
операцию, а также быструю проверку работоспособности в виде сумм строк и столбцов: