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

Вход

Регистрация

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

 

= Мир MS Excel/Range -> Array -> Range (UDF) - Мир MS Excel

Старая форма входа
  • Страница 1 из 1
  • 1
Модератор форума: китин, _Boroda_  
Range -> Array -> Range (UDF)
Mike Дата: Пятница, 05.04.2013, 22:52 | Сообщение № 1
Группа: Гости
Добрый день! Пишу UDF в Excel 2007. Нужна функция, которая (1) имеет на входе Range, (2) изменяет его размер, (3) изменяет значение отдельных элементов, (4) выдает Rangе. Пункт 4 очень важен, чтобы выдавал именно Range, а не Array, т.к. в дальнейшем функции подцепляют именно Range из данной.

Составил код (смысловой нагрузки не несет):
******************************
[vba]
Код
Function RangeTest(Structure As Range) As Variant

i = 3
Dim temp1 As Range
Dim temp2 As Range
Set temp1 = Structure.Resize(i, 3)

Dim arr1()
ReDim arr1(1 To i, 1 To 3) As Variant
arr1 = temp1
arr1(2, 2) = 100
temp2.Value = arr1

RangeTest = temp1

End Function
[/vba]
******************************

Но он не работает. Варианты с использованием temp2.Value тоже не проходят.

Помогите разобраться с проблемой, пожалуйста.
 
Ответить
СообщениеДобрый день! Пишу UDF в Excel 2007. Нужна функция, которая (1) имеет на входе Range, (2) изменяет его размер, (3) изменяет значение отдельных элементов, (4) выдает Rangе. Пункт 4 очень важен, чтобы выдавал именно Range, а не Array, т.к. в дальнейшем функции подцепляют именно Range из данной.

Составил код (смысловой нагрузки не несет):
******************************
[vba]
Код
Function RangeTest(Structure As Range) As Variant

i = 3
Dim temp1 As Range
Dim temp2 As Range
Set temp1 = Structure.Resize(i, 3)

Dim arr1()
ReDim arr1(1 To i, 1 To 3) As Variant
arr1 = temp1
arr1(2, 2) = 100
temp2.Value = arr1

RangeTest = temp1

End Function
[/vba]
******************************

Но он не работает. Варианты с использованием temp2.Value тоже не проходят.

Помогите разобраться с проблемой, пожалуйста.

Автор - Mike
Дата добавления - 05.04.2013 в 22:52
nerv Дата: Суббота, 06.04.2013, 01:36 | Сообщение № 2
Группа: Редакторы
Ранг: Обитатель
Сообщений: 431
Репутация: 193 ±
Замечаний: 0% ±

Предлагаю начать решение вашей проблемы с оформления кода.


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


YM 41001156540584 / WM WMR R21924176233

https://github.com/nervgh/vba
 
Ответить
СообщениеПредлагаю начать решение вашей проблемы с оформления кода.

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

2003
1. Как может не работать код, который не несёт смысловой нагрузки? biggrin
2. Что конкретно не работает и в чём это выражается? Результаты не те? Тогда что ожидали и что получили? Ошибку выдаёт? Тогда какую и на каком операторе?
3. Где размещены данные и код? Если в разных модулях, то при обращении к диапазону для определённости лучше ещё и лист указывать (он почему-то не всегда автоматом определяется по аргументу-диапазону).
Т.е. в Вашем случае вместо [vba]
Код
Set temp1 = Structure.Resize(i, 3)
[/vba] лучше писать [vba]
Код
Set temp1 = Parent(Structure).Structure.Resize(i, 3)
[/vba]
4. Замените [vba]
Код
ReDim arr1(1 To i, 1 To 3) As Variant
arr1 = temp1
[/vba] на [vba]
Код
arr1 = temp1.Value
[/vba]
5. Если Вы хотите, чтобы функция вернула диапазон, то почему у Вас определено [vba]
Код
Function RangeTest(Structure As Range) As Variant
[/vba] а не [vba]
Код
Function RangeTest(Structure As Range) As Range
[/vba]



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


Сообщение отредактировал Alex_ST - Суббота, 06.04.2013, 07:50
 
Ответить
Сообщение1. Как может не работать код, который не несёт смысловой нагрузки? biggrin
2. Что конкретно не работает и в чём это выражается? Результаты не те? Тогда что ожидали и что получили? Ошибку выдаёт? Тогда какую и на каком операторе?
3. Где размещены данные и код? Если в разных модулях, то при обращении к диапазону для определённости лучше ещё и лист указывать (он почему-то не всегда автоматом определяется по аргументу-диапазону).
Т.е. в Вашем случае вместо [vba]
Код
Set temp1 = Structure.Resize(i, 3)
[/vba] лучше писать [vba]
Код
Set temp1 = Parent(Structure).Structure.Resize(i, 3)
[/vba]
4. Замените [vba]
Код
ReDim arr1(1 To i, 1 To 3) As Variant
arr1 = temp1
[/vba] на [vba]
Код
arr1 = temp1.Value
[/vba]
5. Если Вы хотите, чтобы функция вернула диапазон, то почему у Вас определено [vba]
Код
Function RangeTest(Structure As Range) As Variant
[/vba] а не [vba]
Код
Function RangeTest(Structure As Range) As Range
[/vba]

Автор - Alex_ST
Дата добавления - 06.04.2013 в 07:46
Gustav Дата: Суббота, 06.04.2013, 11:59 | Сообщение № 4
Группа: Админы
Ранг: Участник клуба
Сообщений: 2793
Репутация: 1160 ±
Замечаний: ±

начинал с Excel 4.0, видел 2.1
Mike, что-то как-то мудрёно всё... Предлагаю вот так:
[vba]
Код
Function RangeTest(Structure As Range) As Range

     Dim i       As Integer
     Dim arr1    As Variant
      
     i = 3
     Set RangeTest = Structure.Resize(i, 3)
          
     'и всё! возвращаемый диапазон определен! и вычисления ниже
     'никак на его определение уже НЕ ВЛИЯЮТ!
     'ведь Range - это не набор значений (для этого есть массивы),
     'а набор ячеек рабочего листа (почувствуйте разницу!)
      
     arr1 = RangeTest
     arr1(2, 2) = 100
     arr1(3, 2) = 300
     RangeTest = arr1
         
End Function
[/vba]


МОИ: Ник, Tip box: 41001663842605
 
Ответить
СообщениеMike, что-то как-то мудрёно всё... Предлагаю вот так:
[vba]
Код
Function RangeTest(Structure As Range) As Range

     Dim i       As Integer
     Dim arr1    As Variant
      
     i = 3
     Set RangeTest = Structure.Resize(i, 3)
          
     'и всё! возвращаемый диапазон определен! и вычисления ниже
     'никак на его определение уже НЕ ВЛИЯЮТ!
     'ведь Range - это не набор значений (для этого есть массивы),
     'а набор ячеек рабочего листа (почувствуйте разницу!)
      
     arr1 = RangeTest
     arr1(2, 2) = 100
     arr1(3, 2) = 300
     RangeTest = arr1
         
End Function
[/vba]

Автор - Gustav
Дата добавления - 06.04.2013 в 11:59
Mike Дата: Суббота, 06.04.2013, 12:51 | Сообщение № 5
Группа: Гости
Спасибо за комментарии! Уточню вопрос.
Есть Range в Excel, задается через Name и условно называется Structure. Изначально обращался к этому Range для вычислений на основе элементов Range, например,

[vba]
Код
Function NumberofRows(Structure As Range) As Variant
i = 2
Set NumberofRows= Structure.Rows.Count
End Function
[/vba]

где вычисляется количество строк в начальном Range. Используются и другие функции, но все берут Structure As Range в качестве аргумента.

Далее - появилась необходимость изменить начальный Range: сократить его и изменить значения отдельных элементов. При этом делать на spreadsheet'е новый Range и называть его, скажем - Structure2, не надо. Предполагается, что будет использована функция вида NumberofRows(Rangetest(Structure)) или SumOfCells(Rangetest(Structure)). Для этого создана функция Rangetest.

Сейчас функция имеет вид (после работы над ошибками:)

[vba]
Код
Function Rangetest(Structure As Range) As Range
Dim i As Long
i = 3
Set Rangetest= Structure.Resize(i, 3)
End Function
[/vba]

То есть сейчас функция Rangetest меняет размер Range. Более того функция NumberofRows(Rangetest(Structure)) выдает 3, т.е. количество строк в новом Range, как и должно быть.

Однако если изменять значения в новом Range, например, так

[vba]
Код
Function Rangetest(Structure As Range) As Range
Dim i As Long
i = 3
Set Rangetest= Structure.Resize(i, 3)
Rangetest.Cells(2.2).Value = 100
End Function
[/vba]

то выдается ошибка #VALUE!.

Собственно вопрос: какой вид должна иметь функция Rangetest, чтобы корректно работала NumberofRows(Rangetest(Structure))? Важно: функция Rangetest должна не только менять размер начального Range, но и значения отдельных элементов.

Комментарии:
1) smile
2) постарался описать выше
3) весь код - в одном модуле, данные - на spreadsheet. Данным присвоено значание через Name.
4) как писал выше, элемент .Value вызывает ошибку.
5) исправил, спасибо
 
Ответить
СообщениеСпасибо за комментарии! Уточню вопрос.
Есть Range в Excel, задается через Name и условно называется Structure. Изначально обращался к этому Range для вычислений на основе элементов Range, например,

[vba]
Код
Function NumberofRows(Structure As Range) As Variant
i = 2
Set NumberofRows= Structure.Rows.Count
End Function
[/vba]

где вычисляется количество строк в начальном Range. Используются и другие функции, но все берут Structure As Range в качестве аргумента.

Далее - появилась необходимость изменить начальный Range: сократить его и изменить значения отдельных элементов. При этом делать на spreadsheet'е новый Range и называть его, скажем - Structure2, не надо. Предполагается, что будет использована функция вида NumberofRows(Rangetest(Structure)) или SumOfCells(Rangetest(Structure)). Для этого создана функция Rangetest.

Сейчас функция имеет вид (после работы над ошибками:)

[vba]
Код
Function Rangetest(Structure As Range) As Range
Dim i As Long
i = 3
Set Rangetest= Structure.Resize(i, 3)
End Function
[/vba]

То есть сейчас функция Rangetest меняет размер Range. Более того функция NumberofRows(Rangetest(Structure)) выдает 3, т.е. количество строк в новом Range, как и должно быть.

Однако если изменять значения в новом Range, например, так

[vba]
Код
Function Rangetest(Structure As Range) As Range
Dim i As Long
i = 3
Set Rangetest= Structure.Resize(i, 3)
Rangetest.Cells(2.2).Value = 100
End Function
[/vba]

то выдается ошибка #VALUE!.

Собственно вопрос: какой вид должна иметь функция Rangetest, чтобы корректно работала NumberofRows(Rangetest(Structure))? Важно: функция Rangetest должна не только менять размер начального Range, но и значения отдельных элементов.

Комментарии:
1) smile
2) постарался описать выше
3) весь код - в одном модуле, данные - на spreadsheet. Данным присвоено значание через Name.
4) как писал выше, элемент .Value вызывает ошибку.
5) исправил, спасибо

Автор - Mike
Дата добавления - 06.04.2013 в 12:51
Mike Дата: Суббота, 06.04.2013, 13:15 | Сообщение № 6
Группа: Гости
Просматривал пост, нашел ошибку. Разумеется, функция NumberofRows не имеет Set и выглядит так:

[vba]
Код
Function NumberofRows(Structure As Range) As Variant
i = 2
NumberofRows= Structure.Rows.Count
End Function
[/vba]

Gustav, понимаю ваше замечение относительно Range и Array. Думаю, именно в этом и проблема. Ваш код выдает у меня ошибку #VALUE!. Кроется ошибка во второй части.

[vba]
Код
arr1 = RangeTest
arr1(2, 2) = 100
arr1(3, 2) = 300
RangeTest = arr1
[/vba]

Без этого блока менятся размер Range. С этим блоком - ошибка.
 
Ответить
СообщениеПросматривал пост, нашел ошибку. Разумеется, функция NumberofRows не имеет Set и выглядит так:

[vba]
Код
Function NumberofRows(Structure As Range) As Variant
i = 2
NumberofRows= Structure.Rows.Count
End Function
[/vba]

Gustav, понимаю ваше замечение относительно Range и Array. Думаю, именно в этом и проблема. Ваш код выдает у меня ошибку #VALUE!. Кроется ошибка во второй части.

[vba]
Код
arr1 = RangeTest
arr1(2, 2) = 100
arr1(3, 2) = 300
RangeTest = arr1
[/vba]

Без этого блока менятся размер Range. С этим блоком - ошибка.

Автор - Mike
Дата добавления - 06.04.2013 в 13:15
ikki Дата: Суббота, 06.04.2013, 20:30 | Сообщение № 7
Группа: Друзья
Ранг: Старожил
Сообщений: 1906
Репутация: 504 ±
Замечаний: 0% ±

Excel 2003, 2010
ну я не знаю уже...
разве вам и здесь, и на stackoverflow не объяснили, что
Цитата
You can't create a Range from scratch: you can only refer to an existing range.

http://stackoverflow.com/questio....007-vba

а вы всё продолжаете настаивать...
или вы думаете, что вас подло обманывают?

наверное, имеет смысл озвучить вашу исходную задачу и поискать её решение другим способом?
чем вообще вас не устраивает работа с массивами? зачем весь этот огород?


помощь по Excel и VBA
ikki@fxmail.ru, icq 592842413, skype alex.ikki


Сообщение отредактировал ikki - Суббота, 06.04.2013, 20:31
 
Ответить
Сообщениену я не знаю уже...
разве вам и здесь, и на stackoverflow не объяснили, что
Цитата
You can't create a Range from scratch: you can only refer to an existing range.

http://stackoverflow.com/questio....007-vba

а вы всё продолжаете настаивать...
или вы думаете, что вас подло обманывают?

наверное, имеет смысл озвучить вашу исходную задачу и поискать её решение другим способом?
чем вообще вас не устраивает работа с массивами? зачем весь этот огород?

Автор - ikki
Дата добавления - 06.04.2013 в 20:30
Mike Дата: Суббота, 06.04.2013, 21:07 | Сообщение № 8
Группа: Гости
Исходная задача такова. Есть Range на листе в Excel:
1 2 3 5
5 6 7 8
9 10 11 12
13 14 15 16
17 18 19 20
На основе данного Range выполняются функции, скажем, сумма всех элементов. Таких функций около двух десятков (пример был выше), а самих Range несколько тысяч. Большинство функций имеют Range в качестве аргумента.
Появилась задача работать с измененным Range, без того, чтобы менять исходный вручную.
Значения в Range могут менятся при соблюдении определенных условий, но будут иметь вид:
1 2 3
4 20 7
9 10 100
То есть Range укорачивается, а один или несколько элементов должны поменть значение.

Вопрос: как преобразовать исходный Range, чтобы новый подходил в качестве аргумента для существующих функций.
Вопрос 2: если это невозможно, есть ли альтернативное решение с помощью массивов? предложите, пожалуйста.

Да, на StackOverFlow тоже мой пост, там тоже пока без решений. Не явлюсь профессиональным программистом, обратился за помощью к экспертам.
 
Ответить
СообщениеИсходная задача такова. Есть Range на листе в Excel:
1 2 3 5
5 6 7 8
9 10 11 12
13 14 15 16
17 18 19 20
На основе данного Range выполняются функции, скажем, сумма всех элементов. Таких функций около двух десятков (пример был выше), а самих Range несколько тысяч. Большинство функций имеют Range в качестве аргумента.
Появилась задача работать с измененным Range, без того, чтобы менять исходный вручную.
Значения в Range могут менятся при соблюдении определенных условий, но будут иметь вид:
1 2 3
4 20 7
9 10 100
То есть Range укорачивается, а один или несколько элементов должны поменть значение.

Вопрос: как преобразовать исходный Range, чтобы новый подходил в качестве аргумента для существующих функций.
Вопрос 2: если это невозможно, есть ли альтернативное решение с помощью массивов? предложите, пожалуйста.

Да, на StackOverFlow тоже мой пост, там тоже пока без решений. Не явлюсь профессиональным программистом, обратился за помощью к экспертам.

Автор - Mike
Дата добавления - 06.04.2013 в 21:07
Gustav Дата: Суббота, 06.04.2013, 21:28 | Сообщение № 9
Группа: Админы
Ранг: Участник клуба
Сообщений: 2793
Репутация: 1160 ±
Замечаний: ±

начинал с Excel 4.0, видел 2.1
Цитата (Mike)
Без этого блока менятся размер Range. С этим блоком - ошибка.

Да, я упустил, что это UDF и что Вы эту функцию хотите на рабочем листе использовать. Вне рабочего листа работает нормально, со всеми присвоениями.

А при использовании на рабочем листе (в ячейках) - не будут работать ни присвоения значений другим ячейкам внутри функции, ни какое-либо форматирование других ячеек. Это и пытаться не стоит. Можно не копать в эту сторону - зря потраченное время.

Мне известен лишь один специальный пример, когда удается сформатировать соседние ячейки. Приводил его я, разумеется biggrin Сейчас попробую найти ссылку... О! Нашёл - функция ЗакрасьСоседа: http://www.excelworld.ru/forum/2-1805-1#20032


МОИ: Ник, Tip box: 41001663842605

Сообщение отредактировал Gustav - Суббота, 06.04.2013, 21:37
 
Ответить
Сообщение
Цитата (Mike)
Без этого блока менятся размер Range. С этим блоком - ошибка.

Да, я упустил, что это UDF и что Вы эту функцию хотите на рабочем листе использовать. Вне рабочего листа работает нормально, со всеми присвоениями.

А при использовании на рабочем листе (в ячейках) - не будут работать ни присвоения значений другим ячейкам внутри функции, ни какое-либо форматирование других ячеек. Это и пытаться не стоит. Можно не копать в эту сторону - зря потраченное время.

Мне известен лишь один специальный пример, когда удается сформатировать соседние ячейки. Приводил его я, разумеется biggrin Сейчас попробую найти ссылку... О! Нашёл - функция ЗакрасьСоседа: http://www.excelworld.ru/forum/2-1805-1#20032

Автор - Gustav
Дата добавления - 06.04.2013 в 21:28
ikki Дата: Суббота, 06.04.2013, 21:38 | Сообщение № 10
Группа: Друзья
Ранг: Старожил
Сообщений: 1906
Репутация: 504 ±
Замечаний: 0% ±

Excel 2003, 2010
Цитата (Mike)
функции, скажем, сумма всех элементов. Таких функций около двух десятков

Цитата (Mike)
Вопрос: как преобразовать исходный Range, чтобы новый подходил в качестве аргумента для существующих функций.

это не "исходная задача".
это - ваш вариант её решения.
тупиковый, к сожалению.

за "два десятка" функций не поручусь smile

вариант для суммы
[vba]
Код
Function mySum(r As Range)
    Dim arr()
    arr = r.Resize(3, 3).Value
    arr(1, 1) = 100
    mySum = fSum(arr)
End Function

Function fSum#(a())
    Dim e, f
      
    For Each e In a
      f = f + e
    Next
    fSum = f
End Function
[/vba]

вызов с листа
Код
=mySum(A1:D4)


файл прикладываю (ваш мы, видимо, уже не дождёмся biggrin )

пс. вам не надоело каждый раз вводить капчу? может, пора уже зарегистрироваться? wink
К сообщению приложен файл: mike.xls (25.5 Kb)


помощь по Excel и VBA
ikki@fxmail.ru, icq 592842413, skype alex.ikki


Сообщение отредактировал ikki - Суббота, 06.04.2013, 21:43
 
Ответить
Сообщение
Цитата (Mike)
функции, скажем, сумма всех элементов. Таких функций около двух десятков

Цитата (Mike)
Вопрос: как преобразовать исходный Range, чтобы новый подходил в качестве аргумента для существующих функций.

это не "исходная задача".
это - ваш вариант её решения.
тупиковый, к сожалению.

за "два десятка" функций не поручусь smile

вариант для суммы
[vba]
Код
Function mySum(r As Range)
    Dim arr()
    arr = r.Resize(3, 3).Value
    arr(1, 1) = 100
    mySum = fSum(arr)
End Function

Function fSum#(a())
    Dim e, f
      
    For Each e In a
      f = f + e
    Next
    fSum = f
End Function
[/vba]

вызов с листа
Код
=mySum(A1:D4)


файл прикладываю (ваш мы, видимо, уже не дождёмся biggrin )

пс. вам не надоело каждый раз вводить капчу? может, пора уже зарегистрироваться? wink

Автор - ikki
Дата добавления - 06.04.2013 в 21:38
Mike Дата: Воскресенье, 07.04.2013, 10:42 | Сообщение № 11
Группа: Гости
Проблему решил. Надо поменять аргументы в функциях типа NumberofRows с Range на массивы, и вычисления во всех функциях вести в массивах, а не в диапазонах. Может, не самый эффективный способ, но с задачей справляется. Спасибо всем за комментарии!
 
Ответить
СообщениеПроблему решил. Надо поменять аргументы в функциях типа NumberofRows с Range на массивы, и вычисления во всех функциях вести в массивах, а не в диапазонах. Может, не самый эффективный способ, но с задачей справляется. Спасибо всем за комментарии!

Автор - Mike
Дата добавления - 07.04.2013 в 10:42
  • Страница 1 из 1
  • 1
Поиск:

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