\сегодня попросили привести пример рекурсии в vba на одном из форумов, решил продублировать здесь. Если у кого-то есть примеры реализации рекурсий на vba, пожалуйста выкладывайте
Данный алгоритм призван "развернуть" массив массивов и собрать его содержимое в коллекцию. [vba]
Code
Sub io() Dim arr() As Variant ' array of arrays Dim col As New Collection
Private Sub Recursion(ByRef arr As Variant, ByRef col As Collection) Dim elem As Variant
For Each elem In arr If IsArray(elem) Then Call Recursion(elem, col) ' <-- it's here Exit Sub Else col.Add elem End If Next End Sub
[/vba]
\сегодня попросили привести пример рекурсии в vba на одном из форумов, решил продублировать здесь. Если у кого-то есть примеры реализации рекурсий на vba, пожалуйста выкладывайте
Данный алгоритм призван "развернуть" массив массивов и собрать его содержимое в коллекцию. [vba]
Code
Sub io() Dim arr() As Variant ' array of arrays Dim col As New Collection
Очень своевременный вопрос! Как раз сейчас навожу последний лоск на процедуру поиска файлов в указанной папке и её поддиректориях. Подобное многократно описывалось, но у меня чуть другие требования к формату вывода и обработке результатов.
Всё отладил, отполировал... И перед тем как положить в свою "копилку" взял и попробовал прогнать её в крутом режиме - найти все файлы в общей папке-свалке на сервере... А там, оказывается, мусора накопилось на 1 ТБ: в 1600 папках 32000 файлов.... В общем, подвесол Excel намертво. На Ctrl+Break и Ctrl+Shift+Break никакой реакции. "По трём пальцам"-то я его, конечно, через 10 минут ожидания кильнул. Но не красиво это как-то. Вот и встал вопрос: а как правильно писать код с длинными циклами (или с рекурсиями) чтобы его выполнение можно было прервать "когда надоест ждать" не убивая при этом Excel и не теряя все несохранённые в открытых документах данные?
DoEvents я в рекурсивную процедуру вставил. Не помогло
Очень своевременный вопрос! Как раз сейчас навожу последний лоск на процедуру поиска файлов в указанной папке и её поддиректориях. Подобное многократно описывалось, но у меня чуть другие требования к формату вывода и обработке результатов.
Всё отладил, отполировал... И перед тем как положить в свою "копилку" взял и попробовал прогнать её в крутом режиме - найти все файлы в общей папке-свалке на сервере... А там, оказывается, мусора накопилось на 1 ТБ: в 1600 папках 32000 файлов.... В общем, подвесол Excel намертво. На Ctrl+Break и Ctrl+Shift+Break никакой реакции. "По трём пальцам"-то я его, конечно, через 10 минут ожидания кильнул. Но не красиво это как-то. Вот и встал вопрос: а как правильно писать код с длинными циклами (или с рекурсиями) чтобы его выполнение можно было прервать "когда надоест ждать" не убивая при этом Excel и не теряя все несохранённые в открытых документах данные?
DoEvents я в рекурсивную процедуру вставил. Не помогло Alex_ST
nilem, сходу не смог прочитать. Видимо дело в однобуквенных переменных...
IgorGo, спасибо за классику )
Предлагаю обсудить вопрос использования рекурсии в VBA. Три случая мы уже разобрали: 1. разбор массива массивов 2. вычисление факториала 3. получение списка файлов в папках произвольной вложенности
Где еще юзать? )
Alex_ST, я в тебе не сомневался
nilem, сходу не смог прочитать. Видимо дело в однобуквенных переменных...
IgorGo, спасибо за классику )
Предлагаю обсудить вопрос использования рекурсии в VBA. Три случая мы уже разобрали: 1. разбор массива массивов 2. вычисление факториала 3. получение списка файлов в папках произвольной вложенности
Option Explicit Private iArr& 'текущее положение в массиве с перестановками Public prst&() 'массив с перестановками
Sub www() Dim a&(), i&, m&, kp&
Range("A1").CurrentRegion.Clear m = 6 'кол-во чисел kp = Application.Fact(m) 'кол-во перестановок
ReDim a&(1 To m), prst&(1 To kp, 1 To m) iArr = 0 For i = 1 To m: a(i) = i: Next i Call Perestanovki(a, m, m) 'генерируем перестановки
Range("A1").Resize(kp, m) = prst End Sub
Private Sub Perestanovki(ByVal arr, m&, n&) 'генерация перестановок Dim i&, tmp& If m = 1 Then iArr = iArr + 1 For i = 1 To n prst(iArr, i) = arr(i) Next i Else For i = m To 1 Step -1 tmp = arr(i): arr(i) = arr(m): arr(m) = tmp Call Perestanovki(arr, m - 1, n) Next i End If End Sub
[/vba]
Quote (nerv)
Где еще юзать? )
Генерация перестановок: [vba]
Code
Option Explicit Private iArr& 'текущее положение в массиве с перестановками Public prst&() 'массив с перестановками
Sub www() Dim a&(), i&, m&, kp&
Range("A1").CurrentRegion.Clear m = 6 'кол-во чисел kp = Application.Fact(m) 'кол-во перестановок
ReDim a&(1 To m), prst&(1 To kp, 1 To m) iArr = 0 For i = 1 To m: a(i) = i: Next i Call Perestanovki(a, m, m) 'генерируем перестановки
Range("A1").Resize(kp, m) = prst End Sub
Private Sub Perestanovki(ByVal arr, m&, n&) 'генерация перестановок Dim i&, tmp& If m = 1 Then iArr = iArr + 1 For i = 1 To n prst(iArr, i) = arr(i) Next i Else For i = m To 1 Step -1 tmp = arr(i): arr(i) = arr(m): arr(m) = tmp Call Perestanovki(arr, m - 1, n) Next i End If End Sub
При работе с двоичным деревом рекурсии на каждом углу. У себя в при нечётком сравнении строк использовал для "выравнивания" дерева по глубине (модуль TreeAdjst) [vba]
Code
Option Explicit
Private theSortedList() As Integer Private theBlncTree() As Integer
Public Sub AdjustTreeDepth(ByRef binTree() As Integer) Dim n As Integer 'Выравнивание двоичного дерева по глубине 'theBlncTree(0, 1) - корень
theBlncTree = binTree ReDim theSortedList(1 To UBound(binTree)) n = FillSortedList(theBlncTree(0, 1), 0) theBlncTree(0, 1) = HalfByHalf(1, n) binTree = theBlncTree End Sub
Private Function FillSortedList(k As Integer, last As Integer) As Integer 'Рекурсивное заполнение сортированного списка theSortedList из двоичного дерева theBlncTree 'k - индекс текущего узла двоичного дерева 'last - кол-во заполненных позиций списка
If theBlncTree(k, 1) > 0 Then last = FillSortedList(theBlncTree(k, 1), last) last = last + 1 theSortedList(last) = k If theBlncTree(k, 2) > 0 Then last = FillSortedList(theBlncTree(k, 2), last) FillSortedList = last End Function
Private Function HalfByHalf(a As Integer, b As Integer) As Integer 'Рекурсивное заполнение дерева theBlncTree делением списка пополам theSortedList 'a, b - границы текущего фрагмента списка Dim c As Integer
c = Int((a + b) / 2) HalfByHalf = theSortedList(c) If c > a Then theBlncTree(HalfByHalf, 1) = HalfByHalf(a, c - 1) Else theBlncTree(HalfByHalf, 1) = 0 End If If c < b Then theBlncTree(HalfByHalf, 2) = HalfByHalf(c + 1, b) Else theBlncTree(HalfByHalf, 2) = 0 End If
End Function
[/vba]
Quote (nerv)
Где еще юзать? )
При работе с двоичным деревом рекурсии на каждом углу. У себя в при нечётком сравнении строк использовал для "выравнивания" дерева по глубине (модуль TreeAdjst) [vba]
Code
Option Explicit
Private theSortedList() As Integer Private theBlncTree() As Integer
Public Sub AdjustTreeDepth(ByRef binTree() As Integer) Dim n As Integer 'Выравнивание двоичного дерева по глубине 'theBlncTree(0, 1) - корень
theBlncTree = binTree ReDim theSortedList(1 To UBound(binTree)) n = FillSortedList(theBlncTree(0, 1), 0) theBlncTree(0, 1) = HalfByHalf(1, n) binTree = theBlncTree End Sub
Private Function FillSortedList(k As Integer, last As Integer) As Integer 'Рекурсивное заполнение сортированного списка theSortedList из двоичного дерева theBlncTree 'k - индекс текущего узла двоичного дерева 'last - кол-во заполненных позиций списка
If theBlncTree(k, 1) > 0 Then last = FillSortedList(theBlncTree(k, 1), last) last = last + 1 theSortedList(last) = k If theBlncTree(k, 2) > 0 Then last = FillSortedList(theBlncTree(k, 2), last) FillSortedList = last End Function
Private Function HalfByHalf(a As Integer, b As Integer) As Integer 'Рекурсивное заполнение дерева theBlncTree делением списка пополам theSortedList 'a, b - границы текущего фрагмента списка Dim c As Integer
c = Int((a + b) / 2) HalfByHalf = theSortedList(c) If c > a Then theBlncTree(HalfByHalf, 1) = HalfByHalf(a, c - 1) Else theBlncTree(HalfByHalf, 1) = 0 End If If c < b Then theBlncTree(HalfByHalf, 2) = HalfByHalf(c + 1, b) Else theBlncTree(HalfByHalf, 2) = 0 End If
Ещё один пример рекурсивного вычисления - в топике Перенести настройки Excel на другой компьютер Там самодельные кнопки, меню и подменю Exlel-2003 с неизвестной степенью вложенности перенастраиваются на новое положеник Personal.xls
Ещё один пример рекурсивного вычисления - в топике Перенести настройки Excel на другой компьютер Там самодельные кнопки, меню и подменю Exlel-2003 с неизвестной степенью вложенности перенастраиваются на новое положеник Personal.xlsAlex_ST
nilem, ну зачем же сразу обижаться, посты удалять? Я, например, последние два алгоритма тоже не понял с ходу, это же не значит, что их нужно удалить? ) Предлагаю Вам выложить Вам алгоритм и еще раз объяснить что он делает (кажется что-то с ключами словаря). Между прочим, алгоритмы с рекурсий, наподобии того, который привел Формуляр, очень трудно понять именно из-за ее наличия.
Если вы запустите мой пример в пошаговом режиме, то поймете, для чего там эта Exit Sub. [vba]
Code
Call Recursion(elem, col) Exit Sub ' <--
[/vba] Потому, что когда начинается подъем, то вообще мама дорогая. Попробуй проверни все это в голове глядя на код...
nilem, ну зачем же сразу обижаться, посты удалять? Я, например, последние два алгоритма тоже не понял с ходу, это же не значит, что их нужно удалить? ) Предлагаю Вам выложить Вам алгоритм и еще раз объяснить что он делает (кажется что-то с ключами словаря). Между прочим, алгоритмы с рекурсий, наподобии того, который привел Формуляр, очень трудно понять именно из-за ее наличия.
Если вы запустите мой пример в пошаговом режиме, то поймете, для чего там эта Exit Sub. [vba]
Code
Call Recursion(elem, col) Exit Sub ' <--
[/vba] Потому, что когда начинается подъем, то вообще мама дорогая. Попробуй проверни все это в голове глядя на код...nerv
Чебурашка стал символом олимпийских игр. А чего достиг ты? Тишина - самый громкий звук