VBA: добавление случайных чисел в сетку, которые еще не в сетке
Sub FWP()
Dim i As Integer
Dim j As Integer
Dim n As Integer
n = Range("A1").Value
For i = 1 To n
For j = 1 To n
If Cells(i + 1, j) = 0 Then
Cells(i + 1, j).Value = Int(((n ^ 2) - 1 + 1) * Rnd + 1)
ElseIf Cells(i + 1, j) <> 0 Then
Cells(i + 1, j).Value = Cells(i + 1, j).Value
End If
Next j
Next i
Я пытаюсь выполнить часть домашнего задания, в котором предлагается заполнить пропущенные пробелы в магическом квадрате в VBA. Он настроен как (n x n)
матрица с n^2 числами в; пробелы, которые мне нужно заполнить, представлены нулями в матрице. Пока у меня есть некоторый код, который проходит проверку каждого отдельного значения ячейки и оставит значения в покое, если не 0, и если значение равно 0, он заменяет их случайным числом от 1 до n^2. Проблема в том, что, очевидно, я получаю несколько повторяющихся значений, что недопустимо, должно быть только 1 из каждого числа.
Как мне его кодировать, чтобы в сетке не было повторяющихся чисел? Я пытаюсь включить функцию проверки, чтобы увидеть, есть ли они уже в сетке, но я не уверен, как это сделать
Спасибо
2 ответа
Есть много подходов, которые вы можете использовать, но @CMArg прав, говоря, что массив или словарь - хороший способ убедиться, что у вас нет дубликатов.
Чего вы хотите избежать, так это сценария, в котором каждая ячейка занимает все больше времени для заполнения. Это не проблема для очень маленьких квадратов (например, 10х10), но очень большие квадраты могут стать некрасивыми. (Если ваш диапазон составляет 1-100, а все числа, кроме 31, уже есть в таблице, потребуется много времени - в среднем 100 догадок, верно?- чтобы вытянуть одно неиспользуемое число. Если диапазон равен 1-40000 (200x200), для заполнения последней ячейки потребуется 40000 догадок.)
Поэтому вместо того, чтобы хранить список уже использованных чисел, подумайте о том, как можно эффективно пройти и "вычеркнуть" уже использованные числа, чтобы каждая новая ячейка заняла ровно 1 "предположение" для заполнения.
Вот один из способов, которым вы можете реализовать это:
Класс: SingleRandoms
Option Explicit
Private mUnusedValues As Scripting.Dictionary
Private mUsedValues As Scripting.Dictionary
Private Sub Class_Initialize()
Set mUnusedValues = New Scripting.Dictionary
Set mUsedValues = New Scripting.Dictionary
End Sub
Public Sub GenerateRange(minimumNumber As Long, maximumNumber As Long)
Dim i As Long
With mUnusedValues
.RemoveAll
For i = minimumNumber To maximumNumber
.Add i, i
Next
End With
End Sub
Public Function GetRandom() As Long
Dim i As Long, keyID As Long
Randomize timer
With mUnusedValues
i = .Count
keyID = Int(Rnd * i)
GetRandom = .Keys(keyID)
.Remove GetRandom
End With
mUsedValues.Add GetRandom, GetRandom
End Function
Public Property Get AvailableValues() As Scripting.Dictionary
Set AvailableValues = mUnusedValues
End Property
Public Property Get UsedValues() As Scripting.Dictionary
Set UsedValues = mUsedValues
End Property
Пример класса в действии:
Public Sub getRandoms()
Dim r As SingleRandoms
Set r = New SingleRandoms
With r
.GenerateRange 1, 100
Do Until .AvailableValues.Count = 0
Debug.Print .GetRandom()
Loop
End With
End Sub
Использование коллекции на самом деле было бы более эффективным в использовании памяти и быстрее, чем использование словаря, но словарь облегчает проверку того, что он делает то, что должен (поскольку вы можете использовать .Exists
, так далее.).
Никто не собирается делать за тебя домашнее задание. Вы бы только обманывали себя. Позор им, если они делают.
Я не уверен, насколько требователен ваш учитель, но есть много способов решить это.
Вы можете поместить значения матрицы в массив. Проверьте, существует ли элемент с нулевым значением, если нет, прервите. Затем получите ваше потенциальное случайное число для вставки. Итерация по массиву с циклом for, проверяющим каждый элемент на это значение. Если его нет, замените нулевой элемент.