Домашняя страница Undo Do New Save Карта сайта Обратная связь Поиск по форуму
МИР MS EXCEL - Гость.xls

Вход

Регистрация

Напомнить пароль

 

= Мир MS Excel/Рекурсия в VBA - Мир MS Excel

Старая форма входа
  • Страница 1 из 1
  • 1
Модератор форума: китин, _Boroda_  
Рекурсия в VBA
nerv Дата: Четверг, 21.06.2012, 22:45 | Сообщение № 1
Группа: Редакторы
Ранг: Обитатель
Сообщений: 431
Репутация: 193 ±
Замечаний: 0% ±

\сегодня попросили привести пример рекурсии в vba на одном из форумов, решил продублировать здесь. Если у кого-то есть примеры реализации рекурсий на vba, пожалуйста выкладывайте smile

Данный алгоритм призван "развернуть" массив массивов и собрать его содержимое в коллекцию.
[vba]
Code
Sub io()
     Dim arr() As Variant        ' array of arrays
     Dim col As New Collection
      
     arr = Array(1, 2, _
             Array(3, 4, _
                 Array(5, 6, _
                     Array(7, 8, 9) _
                 ) _
             ) _
         )

     Call Recursion(arr, col)
     Stop
End Sub

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]


Чебурашка стал символом олимпийских игр. А чего достиг ты?
Тишина - самый громкий звук


YM 41001156540584 / WM WMR R21924176233

https://github.com/nervgh/vba


Сообщение отредактировал nerv - Четверг, 21.06.2012, 22:53
 
Ответить
Сообщение\сегодня попросили привести пример рекурсии в vba на одном из форумов, решил продублировать здесь. Если у кого-то есть примеры реализации рекурсий на vba, пожалуйста выкладывайте smile

Данный алгоритм призван "развернуть" массив массивов и собрать его содержимое в коллекцию.
[vba]
Code
Sub io()
     Dim arr() As Variant        ' array of arrays
     Dim col As New Collection
      
     arr = Array(1, 2, _
             Array(3, 4, _
                 Array(5, 6, _
                     Array(7, 8, 9) _
                 ) _
             ) _
         )

     Call Recursion(arr, col)
     Stop
End Sub

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]

Автор - nerv
Дата добавления - 21.06.2012 в 22:45
IgorGo Дата: Пятница, 22.06.2012, 02:17 | Сообщение № 2
Группа: Друзья
Ранг: Форумчанин
Сообщений: 108
Репутация: 38 ±
Замечаний: 0% ±

видимо, самый классический вариант функция факториал:
[vba]
Code
Function Fac(ByVal n As Long) As Double
   If n = 0 Then Fac = 1 Else Fac = n * Fac(n - 1)
End Function
[/vba]
 
Ответить
Сообщениевидимо, самый классический вариант функция факториал:
[vba]
Code
Function Fac(ByVal n As Long) As Double
   If n = 0 Then Fac = 1 Else Fac = n * Fac(n - 1)
End Function
[/vba]

Автор - IgorGo
Дата добавления - 22.06.2012 в 02:17
Alex_ST Дата: Пятница, 22.06.2012, 13:46 | Сообщение № 3
Группа: Друзья
Ранг: Участник клуба
Сообщений: 3213
Репутация: 609 ±
Замечаний: 0% ±

2003
Очень своевременный вопрос!
Как раз сейчас навожу последний лоск на процедуру поиска файлов в указанной папке и её поддиректориях.
Подобное многократно описывалось, но у меня чуть другие требования к формату вывода и обработке результатов.

За основу взял процедуру с рекурсивным вызовом функции, предложенную EducatedFool на http://excelvba.ru/code/FilenamesCollection.

Всё отладил, отполировал...
И перед тем как положить в свою "копилку" взял и попробовал прогнать её в крутом режиме - найти все файлы в общей папке-свалке на сервере...
А там, оказывается, мусора накопилось на 1 ТБ: в 1600 папках 32000 файлов....
В общем, подвесол Excel намертво. На Ctrl+Break и Ctrl+Shift+Break никакой реакции. "По трём пальцам"-то я его, конечно, через 10 минут ожидания кильнул.
Но не красиво это как-то.
Вот и встал вопрос: а как правильно писать код с длинными циклами (или с рекурсиями) чтобы его выполнение можно было прервать "когда надоест ждать" не убивая при этом Excel и не теряя все несохранённые в открытых документах данные?

DoEvents я в рекурсивную процедуру вставил. Не помогло sad



С уважением,
Алексей
MS Excel 2003 - the best!!!
 
Ответить
СообщениеОчень своевременный вопрос!
Как раз сейчас навожу последний лоск на процедуру поиска файлов в указанной папке и её поддиректориях.
Подобное многократно описывалось, но у меня чуть другие требования к формату вывода и обработке результатов.

За основу взял процедуру с рекурсивным вызовом функции, предложенную EducatedFool на http://excelvba.ru/code/FilenamesCollection.

Всё отладил, отполировал...
И перед тем как положить в свою "копилку" взял и попробовал прогнать её в крутом режиме - найти все файлы в общей папке-свалке на сервере...
А там, оказывается, мусора накопилось на 1 ТБ: в 1600 папках 32000 файлов....
В общем, подвесол Excel намертво. На Ctrl+Break и Ctrl+Shift+Break никакой реакции. "По трём пальцам"-то я его, конечно, через 10 минут ожидания кильнул.
Но не красиво это как-то.
Вот и встал вопрос: а как правильно писать код с длинными циклами (или с рекурсиями) чтобы его выполнение можно было прервать "когда надоест ждать" не убивая при этом Excel и не теряя все несохранённые в открытых документах данные?

DoEvents я в рекурсивную процедуру вставил. Не помогло sad

Автор - Alex_ST
Дата добавления - 22.06.2012 в 13:46
Alex_ST Дата: Пятница, 22.06.2012, 15:18 | Сообщение № 4
Группа: Друзья
Ранг: Участник клуба
Сообщений: 3213
Репутация: 609 ±
Замечаний: 0% ±

2003
С прерыванием затянувшейся рекурсии разобрался - не там поставил DoEvents smile
Пример выложил в "Решениях" в топике Поиск файлов в папке и её подпапках



С уважением,
Алексей
MS Excel 2003 - the best!!!


Сообщение отредактировал Alex_ST - Пятница, 22.06.2012, 16:08
 
Ответить
СообщениеС прерыванием затянувшейся рекурсии разобрался - не там поставил DoEvents smile
Пример выложил в "Решениях" в топике Поиск файлов в папке и её подпапках

Автор - Alex_ST
Дата добавления - 22.06.2012 в 15:18
nerv Дата: Пятница, 22.06.2012, 16:04 | Сообщение № 5
Группа: Редакторы
Ранг: Обитатель
Сообщений: 431
Репутация: 193 ±
Замечаний: 0% ±

Alex_ST, я в тебе не сомневался smile

nilem, сходу не смог прочитать. Видимо дело в однобуквенных переменных...

IgorGo, спасибо за классику )

Предлагаю обсудить вопрос использования рекурсии в VBA. Три случая мы уже разобрали:
1. разбор массива массивов
2. вычисление факториала
3. получение списка файлов в папках произвольной вложенности

Где еще юзать? )


Чебурашка стал символом олимпийских игр. А чего достиг ты?
Тишина - самый громкий звук


YM 41001156540584 / WM WMR R21924176233

https://github.com/nervgh/vba


Сообщение отредактировал nerv - Пятница, 22.06.2012, 16:05
 
Ответить
СообщениеAlex_ST, я в тебе не сомневался smile

nilem, сходу не смог прочитать. Видимо дело в однобуквенных переменных...

IgorGo, спасибо за классику )

Предлагаю обсудить вопрос использования рекурсии в VBA. Три случая мы уже разобрали:
1. разбор массива массивов
2. вычисление факториала
3. получение списка файлов в папках произвольной вложенности

Где еще юзать? )

Автор - nerv
Дата добавления - 22.06.2012 в 16:04
MCH Дата: Пятница, 22.06.2012, 16:17 | Сообщение № 6
Группа: Админы
Ранг: Старожил
Сообщений: 2004
Репутация: 752 ±
Замечаний: ±

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
[/vba]


Сообщение отредактировал MCH - Пятница, 22.06.2012, 16:20
 
Ответить
Сообщение
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
[/vba]

Автор - MCH
Дата добавления - 22.06.2012 в 16:17
Формуляр Дата: Пятница, 22.06.2012, 16:56 | Сообщение № 7
Группа: Друзья
Ранг: Ветеран
Сообщений: 832
Репутация: 255 ±
Замечаний: 0% ±

Excel 2003, 2013
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
        
End Function
[/vba]


Excel 2003 EN, 2013 EN

Сообщение отредактировал Формуляр - Пятница, 22.06.2012, 16:58
 
Ответить
Сообщение
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
        
End Function
[/vba]

Автор - Формуляр
Дата добавления - 22.06.2012 в 16:56
Alex_ST Дата: Пятница, 22.06.2012, 20:39 | Сообщение № 8
Группа: Друзья
Ранг: Участник клуба
Сообщений: 3213
Репутация: 609 ±
Замечаний: 0% ±

2003
Ещё один пример рекурсивного вычисления - в топике Перенести настройки Excel на другой компьютер
Там самодельные кнопки, меню и подменю Exlel-2003 с неизвестной степенью вложенности перенастраиваются на новое положеник Personal.xls



С уважением,
Алексей
MS Excel 2003 - the best!!!
 
Ответить
СообщениеЕщё один пример рекурсивного вычисления - в топике Перенести настройки Excel на другой компьютер
Там самодельные кнопки, меню и подменю Exlel-2003 с неизвестной степенью вложенности перенастраиваются на новое положеник Personal.xls

Автор - Alex_ST
Дата добавления - 22.06.2012 в 20:39
nerv Дата: Понедельник, 25.06.2012, 10:56 | Сообщение № 9
Группа: Редакторы
Ранг: Обитатель
Сообщений: 431
Репутация: 193 ±
Замечаний: 0% ±

nilem, ну зачем же сразу обижаться, посты удалять? smile Я, например, последние два алгоритма тоже не понял с ходу, это же не значит, что их нужно удалить? ) Предлагаю Вам выложить Вам алгоритм и еще раз объяснить что он делает (кажется что-то с ключами словаря). Между прочим, алгоритмы с рекурсий, наподобии того, который привел Формуляр, очень трудно понять именно из-за ее наличия.

Если вы запустите мой пример в пошаговом режиме, то поймете, для чего там эта Exit Sub.
[vba]
Code
Call Recursion(elem, col)
Exit Sub    ' <--
[/vba]
Потому, что когда начинается подъем, то вообще мама дорогая. Попробуй проверни все это в голове глядя на код...


Чебурашка стал символом олимпийских игр. А чего достиг ты?
Тишина - самый громкий звук


YM 41001156540584 / WM WMR R21924176233

https://github.com/nervgh/vba


Сообщение отредактировал nerv - Понедельник, 25.06.2012, 11:04
 
Ответить
Сообщениеnilem, ну зачем же сразу обижаться, посты удалять? smile Я, например, последние два алгоритма тоже не понял с ходу, это же не значит, что их нужно удалить? ) Предлагаю Вам выложить Вам алгоритм и еще раз объяснить что он делает (кажется что-то с ключами словаря). Между прочим, алгоритмы с рекурсий, наподобии того, который привел Формуляр, очень трудно понять именно из-за ее наличия.

Если вы запустите мой пример в пошаговом режиме, то поймете, для чего там эта Exit Sub.
[vba]
Code
Call Recursion(elem, col)
Exit Sub    ' <--
[/vba]
Потому, что когда начинается подъем, то вообще мама дорогая. Попробуй проверни все это в голове глядя на код...

Автор - nerv
Дата добавления - 25.06.2012 в 10:56
Формуляр Дата: Понедельник, 25.06.2012, 11:36 | Сообщение № 10
Группа: Друзья
Ранг: Ветеран
Сообщений: 832
Репутация: 255 ±
Замечаний: 0% ±

Excel 2003, 2013
Quote (nerv)
алгоритмы с рекурсий, наподобии того, который привел Формуляр, очень трудно понять именно из-за ее наличия.

Если такого рода макросы в принципе интересны, готов дописать комментарии.


Excel 2003 EN, 2013 EN
 
Ответить
Сообщение
Quote (nerv)
алгоритмы с рекурсий, наподобии того, который привел Формуляр, очень трудно понять именно из-за ее наличия.

Если такого рода макросы в принципе интересны, готов дописать комментарии.

Автор - Формуляр
Дата добавления - 25.06.2012 в 11:36
nerv Дата: Понедельник, 16.07.2012, 13:35 | Сообщение № 11
Группа: Редакторы
Ранг: Обитатель
Сообщений: 431
Репутация: 193 ±
Замечаний: 0% ±

Quote (Формуляр)
Если такого рода макросы в принципе интересны, готов дописать комментарии.

спасибо. Скорей интересна сама ситуация, в которой можно применить рекурсию.


Чебурашка стал символом олимпийских игр. А чего достиг ты?
Тишина - самый громкий звук


YM 41001156540584 / WM WMR R21924176233

https://github.com/nervgh/vba
 
Ответить
Сообщение
Quote (Формуляр)
Если такого рода макросы в принципе интересны, готов дописать комментарии.

спасибо. Скорей интересна сама ситуация, в которой можно применить рекурсию.

Автор - nerv
Дата добавления - 16.07.2012 в 13:35
  • Страница 1 из 1
  • 1
Поиск:

Яндекс.Метрика Яндекс цитирования
© 2010-2024 · Дизайн: MichaelCH · Хостинг от uCoz · При использовании материалов сайта, ссылка на www.excelworld.ru обязательна!