Я собрал инструмент для генерации случайных перестановок строк / столбцов с помощью нескольких формул и некоторого 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
, а также быструю проверку работоспособности в виде сумм строк и столбцов: