3 вложенных цикла в массиве — VBA

#arrays #excel #vba #loops

#массивы #превосходить #vba #петли

Вопрос:

У меня есть 2 вложенных цикла в массиве, но, насколько я понимаю, мне нужен третий, который я не в состоянии реализовать.

У меня есть следующие данные (желтым цветом):

введите описание изображения здесь

Текущий код вычисляется, как указано в столбце Фактическое поведение:

 Dim arr, outarr as Variant Dim lastc, lastr as long  lastc = 2 lastr = Cells(ws.Rows.count, lastc).End(xlUp).Row  arr = Range(Cells(2, lastc), Cells(lastr, lastc))  cnt = ((UBound(arr, 1) - 1) * UBound(arr, 1)) / 2  k = 1  ReDim outarr(1 To cnt, 1 To 1)  For i = LBound(arr, 1)   1 To UBound(arr, 1)  For j = LBound(arr, 1) To i - 1  outarr(k, 1) = arr(j, 1) - arr(i, 1)    k = k   1  Next j  Next i  

Желаемое поведение было бы для значений от 1.1 до 6.1, чтобы в результате сохранить минимальное значение в этом диапазоне. 10 — 0 = 10, но мне нужно фактическое минимальное значение в этом диапазоне (от 1,6 до 6,6), а минимальное значение будет 10 — 40 = -30.

Действительно важно, чтобы минимальное значение всегда вычислялось как первое значение диапазона — X значения диапазона. Первое значение в данном цикле является константой.

Я считаю, что третий цикл необходим для хранения минимального значения, а затем вставьте это значение в outarr, но пока мне это не удалось.

Спасибо вам за вашу помощь.

Комментарии:

1. Я не уверен, правильно ли я понимаю часть минимального значения.. Для B7-B3 , разве минимальное значение не будет 5 - 40 ? и B7-B2 , минимальное значение будет 0 - 40 ?

2. @Raymond Wu Обновил мой запрос. Спасибо, что указали на это. Первое значение в диапазоне является константой, расчет основан на (первое значение — значение X, первое значение — значение Y…..).

3. Извините, я все еще не понимаю, потому B5-B3 что выход равен 25 , но разве это не минимум 30 - 40 ?

4. @Raymond Wu Да, вы правы. Я просто не рассчитал это, так как желаемое поведение объясняется в примере B7. Но да, минимум будет — 10.

5. @Raymond У меня еще один вопрос, Рэймонд. Этот цикл является частью большего цикла, и когда я пытаюсь получить доступ к следующему циклу, outputindex увеличивается на 1. Есть идеи, почему? Количество строк, размер массива-все идентично. Спасибо.

Ответ №1:

Вместо того, чтобы делать еще один цикл, я записываю наименьшее значение в каждом цикле и сравниваю его с новым значением во внутреннем цикле:

 Option Explicit  Private Sub Test()  Const startRow As Long = 2  Const valueCol As Long = 2  Const outputCol As Long = 4    Dim ws As Worksheet  Set ws = ThisWorkbook.Worksheets("Sheet1")    Dim lastRow As Long  lastRow = ws.Cells(ws.Rows.Count, valueCol).End(xlUp).Row    Dim inputArr As Variant  inputArr = ws.Range(ws.Cells(startRow, valueCol), ws.Cells(lastRow, valueCol)).Value    Dim outputSize As Long  outputSize = ((UBound(inputArr, 1) - 1) * UBound(inputArr, 1)) / 2    Dim outputIndex As Long  Dim outputArr As Variant  ReDim outputArr(1 To outputSize, 1 To 1) As Variant    Dim i As Long  Dim n As Long    Dim currFirst As Long  Dim currLowest As Long    For i = 2 To UBound(inputArr, 1)  currFirst = inputArr(i, 1)  currLowest = currFirst - inputArr(i - 1, 1)    For n = i - 1 To 1 Step -1  Dim testLowest As Long  testLowest = currFirst - inputArr(n, 1)    If testLowest lt; currLowest Then currLowest = testLowest    outputIndex = outputIndex   1  outputArr(outputIndex, 1) = currLowest  Next n  Next i    ws.Cells(startRow, outputCol).Resize(UBound(outputArr, 1)).Value = outputArr End Sub  

введите описание изображения здесь

Комментарии:

1. Спасибо тебе, Рэймонд. Пришлось внести изменения в некоторые части кода, чтобы удовлетворить мои потребности, но работает отлично.

Ответ №2:

Я считаю, что это дает желаемые результаты.

Вместо того, чтобы добавлять 3-й вложенный цикл в микс, я добавил дополнительный вспомогательный цикл на первый уровень.

Пожалуйста, обратите внимание: это должно дать вам хорошее представление о том, как подойти к этому с меньшей сложностью, чем к другому уровню For Next цикла, но из-за позиционирования производительность будет снижаться по мере роста итераций.

Я переименовал некоторые переменные, чтобы они были более описательными (за исключением x того, что я обленился).

Объяснение находится ниже кода, вот переработанный раздел цикла.

 OutputCounter = 1 For LayerOneStep = LBound(ValueArray, 1) To UBound(ValueArray, 1)  ReDim TempArray(1 To LayerOneStep)  For x = 1 To UBound(TempArray)  TempArray(x) = ValueArray(x, 1)  Next x  For LayerTwoStep = LBound(ValueArray, 1) To LayerOneStep - 1  MaxValue = WorksheetFunction.Max(TempArray)  TempValue = (ValueArray(LayerOneStep, 1) - ValueArray(LayerTwoStep, 1))  If ValueArray(LayerOneStep, 1) = 0 Or ValueArray(LayerTwoStep, 1) = 0 Then  OutputArray(OutputCounter) = TempValue  OutputCounter = OutputCounter   1  ElseIf TempValue lt; ValueArray(LayerOneStep, 1) - MaxValue Then  OutputArray(OutputCounter) = TempValue  OutputCounter = OutputCounter   1  Else  OutputArray(OutputCounter) = ValueArray(LayerOneStep, 1) - MaxValue  OutputCounter = OutputCounter   1  End If  Next LayerTwoStep Next LayerOneStep  
  • TempArray() используется для хранения ваших сгруппированных значений. Т. е. B3 amp; B2 или B5 amp; B4 amp; B3 amp; B2 и т. Д. Это достигается путем присвоения значений из столбца B строки 2 независимо от того, до какой строки находится счетчик LayerOne. Значения назначаются из существующего ValueArray массива, а не каждый раз повторно обращаются к рабочему листу.
  • Назначение его таким образом позволяет нам использовать WorksheetFunction.Max() функцию для поиска наибольшего числа в наборе. (имейте в виду, как указано выше, не самый эффективный способ)
  • Затем мы используем некоторые переменные для назначения некоторых вычислений. MaxValue Как указано выше, и TempValue это подход x-y — тот же результат, что и формулы рабочего листа.
  • Затем мы используем некоторую If...Then...Else логику, чтобы начать разработку абсолютного минимального значения на основе диапазона вычислений.
  • If Условия Fist проверяют, является ли какое-либо значение частью TempValue вычисления равным нулю (0). Если это так, он возвращает некоторые забавные результаты, так что это гарантирует, что мы перейдем к результату x — 0 или 0 — y OutputArray .
  • Во — вторых, проверяется, соответствует ли TempValue вычисление значению меньше x — MaxValue . Если да, то он возвращается TempValue в OutputArray .
  • В противном случае мы возвращаем x — MaxValue в OutputArray .

Результат вышеупомянутого кодекса;

Фрагмент результатов выполненного кода, записанного обратно на рабочий лист