AndreA SN 1014 / 118 / 2 Регистрация: 26.08.2011 Сообщений: 1,113 Записей в блоге: 2 |
||||
1 |
||||
Как проверить пуст ли массив?22.07.2015, 09:47. Показов 29881. Ответов 42 Метки нет (Все метки)
это продолжение темы. интересует грамотность записи
Добавлено через 1 минуту
0 |
3827 / 2254 / 751 Регистрация: 02.11.2012 Сообщений: 5,930 |
|
22.07.2015, 10:13 |
2 |
чтобы не было нулевой позиции перед внесением проверять.
0 |
1014 / 118 / 2 Регистрация: 26.08.2011 Сообщений: 1,113 Записей в блоге: 2 |
|
22.07.2015, 11:12 [ТС] |
3 |
Vlad999, согласен. Я постоянно так и делаю. Но проверять постоянно есть-ли запись в первой строке — это увеличение операций по заполнению массива в 2 раза. Вот я и спрашиваю: какие технологии заполнения массивов спецами используются. Чтобы не было лишних проверок состояния массива на «полный, пустой»
0 |
1337 / 308 / 74 Регистрация: 13.11.2008 Сообщений: 635 |
|
22.07.2015, 11:53 |
4 |
Трудно что-то советовать, когда не видно как Вы этот массив заполнять собрались.
0 |
AndreA SN 1014 / 118 / 2 Регистрация: 26.08.2011 Сообщений: 1,113 Записей в блоге: 2 |
||||
22.07.2015, 12:37 [ТС] |
5 |
|||
The_Prist, привожу пример
В первой части If заполняю первую позицию массива, а в части Else — постоянно проверяю на заполненность первую строку. Вот эта необходимость постоянной проверки вызывает вопрос.
0 |
The_Prist 1337 / 308 / 74 Регистрация: 13.11.2008 Сообщений: 635 |
||||
22.07.2015, 12:50 |
6 |
|||
Сообщение было отмечено AndreA SN как решение Решение И все же не видно как объявлен этот массив. Где строка объявления Iskl2?
1 |
AndreA SN 1014 / 118 / 2 Регистрация: 26.08.2011 Сообщений: 1,113 Записей в блоге: 2 |
||||
22.07.2015, 13:00 [ТС] |
7 |
|||
The_Prist, извиняюсь… проглядел ответный вопрос об объявлении массива
в связке с этим вопросом интересует просто вопрос грамотной проверки массива на непустотность Добавлено через 2 минуты
0 |
Dragokas 17992 / 7618 / 890 Регистрация: 25.12.2011 Сообщений: 11,351 Записей в блоге: 17 |
||||
22.07.2015, 13:44 |
8 |
|||
Смотря что считать пустым массивом…
2 |
4038 / 1423 / 394 Регистрация: 07.08.2013 Сообщений: 3,541 |
|
22.07.2015, 13:51 |
9 |
а массивы большие
0 |
1014 / 118 / 2 Регистрация: 26.08.2011 Сообщений: 1,113 Записей в блоге: 2 |
|
22.07.2015, 13:52 [ТС] |
10 |
Dragokas, спасибо)))
0 |
Dragokas 17992 / 7618 / 890 Регистрация: 25.12.2011 Сообщений: 11,351 Записей в блоге: 17 |
||||
22.07.2015, 14:31 |
11 |
|||
AndreA SN, только не забывайте, что результат операции — это не BOOL, а указатель на SAFEARRAY.
2 |
AndreA SN 1014 / 118 / 2 Регистрация: 26.08.2011 Сообщений: 1,113 Записей в блоге: 2 |
||||
22.07.2015, 14:45 [ТС] |
12 |
|||
snipe, опять же смотря из какого объема действий исходить.
в итоге получаем за счет суммирования 6000000 а по максимальному размеру цикла — читай по Ubound(массив) разница составила 300 раз… Добавлено через 13 минут
If Not Cbool(Not Not arr) Then очень прошу (хотя понимаю, что мой вопрос кошмарит грамотных людей), объяснить все эти Not понятным языком — что за что отвечает.
0 |
Dragokas 17992 / 7618 / 890 Регистрация: 25.12.2011 Сообщений: 11,351 Записей в блоге: 17 |
||||
22.07.2015, 22:31 |
13 |
|||
Сообщение было отмечено AndreA SN как решение РешениеAndreA SN, да. Вы правы. Перемудрил. Можно проще.
Если кратко, то оператор Not кроме основной функции (побитовое отрицание) умеет разыменовывать указатель,
1 |
snipe 4038 / 1423 / 394 Регистрация: 07.08.2013 Сообщений: 3,541 |
||||
23.07.2015, 04:02 |
14 |
|||
AndreA SN, есть 2 функции Join и Split
1 |
4038 / 1423 / 394 Регистрация: 07.08.2013 Сообщений: 3,541 |
|
23.07.2015, 04:09 |
15 |
Dragokas, Миниатюры
0 |
2670 / 786 / 176 Регистрация: 14.01.2013 Сообщений: 3,674 |
|
23.07.2015, 06:54 |
16 |
В Опере всё норм выглядит. Миниатюры
1 |
snipe |
23.07.2015, 09:01
|
Не по теме: так я тоже в опере делал
0 |
1014 / 118 / 2 Регистрация: 26.08.2011 Сообщений: 1,113 Записей в блоге: 2 |
|
23.07.2015, 10:54 [ТС] |
18 |
snipe,
из много массивов сделать один нет… у меня задача другая… я делаю маленький реплик-массив из большого массива. причем оба они двумерны. реплик-массив как правило варьирует от 2 до нескольких десятков записей (встречаются редко случаи и до 2500), а большой массив может включать десятки тысяч записей. Постоянная перезапись реплик-массива с изменяющимися исходными условиями вынуждают при последующей работе проверять : а записалось ли чего-то в реплик-массив, или он при изменившихся условиях отбора записей остался пустым? Вот последнее хочется грамотно проверять, что Dragokas и подсказал как делать. Добавлено через 11 минут
0 |
4038 / 1423 / 394 Регистрация: 07.08.2013 Сообщений: 3,541 |
|
23.07.2015, 11:01 |
19 |
AndreA SN, вы тему разместили в разделе VBA, а в какой программе вы все это делаете?
0 |
1014 / 118 / 2 Регистрация: 26.08.2011 Сообщений: 1,113 Записей в блоге: 2 |
|
23.07.2015, 11:25 [ТС] |
20 |
snipe, толковый вопрос))) мне уже столько людей у виска пальцем крутит по поводу моего проекта в VBA))) И Вы почуяли, что моя задача монстрифицирована. Добавлено через 9 минут
0 |
I want to check for empty arrays. Google gave me varied solutions but nothing worked. Maybe I am not applying them correctly.
Function GetBoiler(ByVal sFile As String) As String
'Email Signature
Dim fso As Object
Dim ts As Object
Set fso = CreateObject("Scripting.FileSystemObject")
Set ts = fso.GetFile(sFile).OpenAsTextStream(1, -2)
GetBoiler = ts.ReadAll
ts.Close
End Function
Dim FileNamesList As Variant, i As Integer
' activate the desired startfolder for the filesearch
FileNamesList = CreateFileList("*.*", False) ' Returns File names
' performs the filesearch, includes any subfolders
' present the result
' If there are Signatures then populate SigString
Range("A:A").ClearContents
For i = 1 To UBound(FileNamesList)
Cells(i + 1, 1).Formula = FileNamesList(i)
Next i
SigString = FileNamesList(3)
If Dir(SigString) <> "" Then
Signature = GetBoiler(SigString)
Else
Signature = ""
End If
Here if FileNamesList
array is empty, GetBoiler(SigString)
should not get called at all. When FileNamesList
array is empty, SigString
is also empty and this calls GetBoiler()
function with empty string. I get an error at line
Set ts = fso.GetFile(sFile).OpenAsTextStream(1, -2)
since sFile
is empty. Any way to avoid that?
Guy
10.7k5 gold badges34 silver badges47 bronze badges
asked Oct 15, 2008 at 20:31
2
Go with a triple negative:
If (Not Not FileNamesList) <> 0 Then
' Array has been initialized, so you're good to go.
Else
' Array has NOT been initialized
End If
Or just:
If (Not FileNamesList) = -1 Then
' Array has NOT been initialized
Else
' Array has been initialized, so you're good to go.
End If
In VB, for whatever reason, Not myArray
returns the SafeArray pointer. For uninitialized arrays, this returns -1. You can Not
this to XOR it with -1, thus returning zero, if you prefer.
(Not myArray) (Not Not myArray)
Uninitialized -1 0
Initialized -someBigNumber someOtherBigNumber
Source
answered Jan 17, 2013 at 15:49
ahuthahuth
1,34911 silver badges15 bronze badges
3
As you are dealing with a string array, have you considered Join?
If Len(Join(FileNamesList)) > 0 Then
answered Oct 15, 2008 at 21:14
FionnualaFionnuala
90.1k7 gold badges110 silver badges148 bronze badges
8
If you test on an array function it’ll work for all bounds:
Function IsVarArrayEmpty(anArray As Variant)
Dim i As Integer
On Error Resume Next
i = UBound(anArray,1)
If Err.number = 0 Then
IsVarArrayEmpty = False
Else
IsVarArrayEmpty = True
End If
End Function
answered Mar 6, 2009 at 19:10
Lance RobertsLance Roberts
22.2k32 gold badges112 silver badges129 bronze badges
3
I see similar answers on here… but not mine…
This is how I am unfortunatley going to deal with it… I like the len(join(arr)) > 0 approach, but it wouldn’t work if the array was an array of emptystrings…
Public Function arrayLength(arr As Variant) As Long
On Error GoTo handler
Dim lngLower As Long
Dim lngUpper As Long
lngLower = LBound(arr)
lngUpper = UBound(arr)
arrayLength = (lngUpper - lngLower) + 1
Exit Function
handler:
arrayLength = 0 'error occured. must be zero length
End Function
answered Jun 26, 2015 at 21:26
PerpostererPerposterer
3293 silver badges8 bronze badges
When writing VBA there is this sentence in my head: «Could be so easy, but…»
Here is what I adopted it to:
Private Function IsArrayEmpty(arr As Variant)
' This function returns true if array is empty
Dim l As Long
On Error Resume Next
l = Len(Join(arr))
If l = 0 Then
IsArrayEmpty = True
Else
IsArrayEmpty = False
End If
If Err.Number > 0 Then
IsArrayEmpty = True
End If
On Error GoTo 0
End Function
Private Sub IsArrayEmptyTest()
Dim a As Variant
a = Array()
Debug.Print "Array is Empty is " & IsArrayEmpty(a)
If IsArrayEmpty(a) = False Then
Debug.Print " " & Join(a)
End If
End Sub
Lance Roberts
22.2k32 gold badges112 silver badges129 bronze badges
answered Apr 1, 2011 at 9:55
BBQ ChefBBQ Chef
6964 gold badges11 silver badges21 bronze badges
2
This code doesn’t do what you expect:
If Dir(SigString) <> "" Then
Signature = GetBoiler(SigString)
Else
Signature = ""
End If
If you pass an empty string (""
) or vbNullString
to Dir
, it will return the name of the first file in the current directory path (the path returned by CurDir$
). So, if SigString
is empty, your If
condition will evaluate to True
because Dir
will return a non-empty string (the name of the first file in the current directory), and GetBoiler
will be called. And if SigString
is empty, the call to fso.GetFile
will fail.
You should either change your condition to check that SigString
isn’t empty, or use the FileSystemObject.FileExists
method instead of Dir
for checking if the file exists. Dir
is tricky to use precisely because it does things you might not expect it to do. Personally, I would use Scripting.FileSystemObject
over Dir
because there’s no funny business (FileExists
returns True
if the file exists, and, well, False
if it doesn’t). What’s more, FileExists
expresses the intent of your code much clearly than Dir
.
Method 1: Check that SigString
is non-empty first
If SigString <> "" And Dir(SigString) <> "" Then
Signature = GetBoiler(SigString)
Else
Signature = ""
End If
Method 2: Use the FileSystemObject.FileExists
method
Dim fso As Object
Set fso = CreateObject("Scripting.FileSystemObject")
If fso.FileExists(SigString) Then
Signature = GetBoiler(SigString)
Else
Signature = ""
End If
answered Oct 15, 2008 at 21:14
Mike SprossMike Spross
7,9596 gold badges49 silver badges75 bronze badges
I am simply pasting below the code by the great Chip Pearson. It works a charm.
Here’s his page on array functions.
I hope this helps.
Public Function IsArrayEmpty(Arr As Variant) As Boolean
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' IsArrayEmpty
' This function tests whether the array is empty (unallocated). Returns TRUE or FALSE.
'
' The VBA IsArray function indicates whether a variable is an array, but it does not
' distinguish between allocated and unallocated arrays. It will return TRUE for both
' allocated and unallocated arrays. This function tests whether the array has actually
' been allocated.
'
' This function is really the reverse of IsArrayAllocated.
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Dim LB As Long
Dim UB As Long
err.Clear
On Error Resume Next
If IsArray(Arr) = False Then
' we weren't passed an array, return True
IsArrayEmpty = True
End If
' Attempt to get the UBound of the array. If the array is
' unallocated, an error will occur.
UB = UBound(Arr, 1)
If (err.Number <> 0) Then
IsArrayEmpty = True
Else
''''''''''''''''''''''''''''''''''''''''''
' On rare occasion, under circumstances I
' cannot reliably replicate, Err.Number
' will be 0 for an unallocated, empty array.
' On these occasions, LBound is 0 and
' UBound is -1.
' To accommodate the weird behavior, test to
' see if LB > UB. If so, the array is not
' allocated.
''''''''''''''''''''''''''''''''''''''''''
err.Clear
LB = LBound(Arr)
If LB > UB Then
IsArrayEmpty = True
Else
IsArrayEmpty = False
End If
End If
End Function
answered Sep 30, 2013 at 13:52
1
Simplified check for Empty Array:
Dim exampleArray() As Variant 'Any Type
If ((Not Not exampleArray) = 0) Then
'Array is Empty
Else
'Array is Not Empty
End If
arghtype
4,34611 gold badges47 silver badges59 bronze badges
answered Oct 21, 2014 at 15:25
1
Here is another way to do it. I have used it in some cases and it’s working.
Function IsArrayEmpty(arr As Variant) As Boolean
Dim index As Integer
index = -1
On Error Resume Next
index = UBound(arr)
On Error GoTo 0
If (index = -1) Then IsArrayEmpty = True Else IsArrayEmpty = False
End Function
answered May 12, 2016 at 15:38
SuryaSurya
211 bronze badge
Based on ahuth’s answer;
Function AryLen(ary() As Variant, Optional idx_dim As Long = 1) As Long
If (Not ary) = -1 Then
AryLen = 0
Else
AryLen = UBound(ary, idx_dim) - LBound(ary, idx_dim) + 1
End If
End Function
Check for an empty array; is_empty = AryLen(some_array)=0
answered Jul 15, 2017 at 22:28
user425678user425678
7107 silver badges16 bronze badges
Public Function IsEmptyArray(InputArray As Variant) As Boolean
On Error GoTo ErrHandler:
IsEmptyArray = Not (UBound(InputArray) >= 0)
Exit Function
ErrHandler:
IsEmptyArray = True
End Function
answered Jan 15, 2014 at 23:14
ZhenyaZhenya
1741 silver badge8 bronze badges
1
You can use the below function to check if variant or string array is empty in vba
Function IsArrayAllocated(Arr As Variant) As Boolean
On Error Resume Next
IsArrayAllocated = IsArray(Arr) And _
Not IsError(LBound(Arr, 1)) And _
LBound(Arr, 1) <= UBound(Arr, 1)
End Function
Sample usage
Public Function test()
Dim Arr(1) As String
Arr(0) = "d"
Dim x As Boolean
x = IsArrayAllocated(Arr)
End Function
answered May 4, 2015 at 8:43
0
Another method would be to do it sooner. You can create a Boolean variable and set it to true once you load data to the array. so all you really need is a simple if statement of when you load data into the array.
answered Feb 11, 2016 at 14:22
To check whether a Byte array is empty, the simplest way is to use the VBA function StrPtr()
.
If the Byte array is empty, StrPtr()
returns 0
; otherwise, it returns a non-zero value (however, it’s not the address to the first element).
Dim ar() As Byte
Debug.Assert StrPtr(ar) = 0
ReDim ar(0 to 3) As Byte
Debug.Assert StrPtr(ar) <> 0
However, it only works with Byte array.
answered Oct 30, 2016 at 6:49
Function IsVarArrayEmpty(anArray As Variant) as boolean
On Error Resume Next
IsVarArrayEmpty = true
IsVarArrayEmpty = UBound(anArray) < LBound(anArray)
End Function
Maybe ubound
crashes and it remains at true, and if ubound < lbound
, it’s empty
cssyphus
37.1k18 gold badges93 silver badges109 bronze badges
answered Sep 30, 2016 at 15:49
PierrePierre
1,0267 silver badges20 bronze badges
I’ll generalize the problem and the Question as intended.
Test assingment on the array, and catch the eventual error
Function IsVarArrayEmpty(anArray as Variant)
Dim aVar as Variant
IsVarArrayEmpty=False
On error resume next
aVar=anArray(1)
If Err.number then '...still, it might not start at this index
aVar=anArray(0)
If Err.number then IsVarArrayEmpty=True ' neither 0 or 1 yields good assignment
EndIF
End Function
Sure it misses arrays with all negative indexes or all > 1… is that likely? in weirdland, yes.
Lance Roberts
22.2k32 gold badges112 silver badges129 bronze badges
answered Nov 12, 2008 at 19:00
jpinto3912jpinto3912
1,4652 gold badges12 silver badges19 bronze badges
1
Personally, I think one of the answers above can be modified to check if the array has contents:
if UBound(ar) > LBound(ar) Then
This handles negative number references and takes less time than some of the other options.
answered Mar 27, 2013 at 20:05
Jim SnyderJim Snyder
391 silver badge3 bronze badges
1
You can check if the array is empty by retrieving total elements count using JScript’s VBArray()
object (works with arrays of variant type, single or multidimensional):
Sub Test()
Dim a() As Variant
Dim b As Variant
Dim c As Long
' Uninitialized array of variant
' MsgBox UBound(a) ' gives 'Subscript out of range' error
MsgBox GetElementsCount(a) ' 0
' Variant containing an empty array
b = Array()
MsgBox GetElementsCount(b) ' 0
' Any other types, eg Long or not Variant type arrays
MsgBox GetElementsCount(c) ' -1
End Sub
Function GetElementsCount(aSample) As Long
Static oHtmlfile As Object ' instantiate once
If oHtmlfile Is Nothing Then
Set oHtmlfile = CreateObject("htmlfile")
oHtmlfile.parentWindow.execScript ("function arrlength(arr) {try {return (new VBArray(arr)).toArray().length} catch(e) {return -1}}"), "jscript"
End If
GetElementsCount = oHtmlfile.parentWindow.arrlength(aSample)
End Function
For me it takes about 0.3 mksec for each element + 15 msec initialization, so the array of 10M elements takes about 3 sec. The same functionality could be implemented via ScriptControl
ActiveX (it is not available in 64-bit MS Office versions, so you can use workaround like this).
answered Aug 5, 2016 at 10:45
omegastripesomegastripes
12.3k4 gold badges44 silver badges95 bronze badges
1
if Ubound(yourArray)>-1 then
debug.print "The array is not empty"
else
debug.print "EMPTY"
end if
answered Dec 1, 2016 at 11:32
Dave PooleDave Poole
9987 silver badges13 bronze badges
0
You can check its count.
Here cid is an array.
if (jsonObject("result")("cid").Count) = 0 them
MsgBox "Empty Array"
I hope this helps.
Have a nice day!
answered Jun 19, 2018 at 16:43
Another solution to test for empty array
if UBound(ar) < LBound(ar) then msgbox "Your array is empty!"
Or, if you already know that LBound is 0
if -1 = UBound(ar) then msgbox "Your array is empty!"
This may be faster than join(). (And I didn’t check with negative indexes)
Here is my sample to filter 2 string arrays so they do not share same strings.
' Filtering ar2 out of strings that exists in ar1
For i = 0 To UBound(ar1)
' filter out any ar2.string that exists in ar1
ar2 = Filter(ar2 , ar1(i), False)
If UBound(ar2) < LBound(ar2) Then
MsgBox "All strings are the same.", vbExclamation, "Operation ignored":
Exit Sub
End If
Next
' At this point, we know that ar2 is not empty and it is filtered
'
mmmmmm
32.1k27 gold badges89 silver badges116 bronze badges
answered Jul 15, 2012 at 10:43
1
Public Function arrayIsEmpty(arrayToCheck() As Variant) As Boolean
On Error GoTo Err:
Dim forCheck
forCheck = arrayToCheck(0)
arrayIsEmpty = False
Exit Function
Err:
arrayIsEmpty = True
End Function
answered Nov 3, 2012 at 17:38
Stefanos KargasStefanos Kargas
10.3k22 gold badges75 silver badges101 bronze badges
1
Массивы в VBA Excel: одномерные, многомерные и динамические. Объявление и использование массивов. Операторы Public, Dim и ReDim. Функции Array, LBound, UBound.
Массивы – это множества однотипных элементов, имеющих одно имя и отличающиеся друг от друга индексами. Они могут быть одномерными (линейными), многомерными и динамическими. Массивы в VBA Excel, как и другие переменные, объявляются с помощью операторов Dim и Public. Для изменения размерности динамических массивов используется оператор ReDim. Массивы с заранее объявленной размерностью называют статическими.
Одномерные массивы
Объявление одномерных (линейных) статических массивов в VBA Excel:
Public Massiv1(9) As Integer Dim Massiv2(1 To 9) As String |
В первом случае публичный массив содержит 10 элементов от 0 до 9 (нижний индекс по умолчанию — 0, верхний индекс — 9), а во втором случае локальный массив содержит 9 элементов от 1 до 9.
По умолчанию VBA Excel считает в массивах нижним индексом нуль, но, при желании, можно сделать нижним индексом по умолчанию единицу, добавив в самом начале модуля объявление «Option Base 1».
Многомерные массивы
Объявление многомерных статических массивов в VBA Excel аналогично объявлению одномерных массивов, но с добавлением размерностей дополнительных измерений через запятую:
‘Массив двухмерный Public Massiv1(3, 6) As Integer ‘Массив трехмерный Dim Massiv2(1 To 6, 1 To 8, 1 To 5) As String ‘Массив четырехмерный Dim Massiv3(9, 9, 9, 9) As Date |
Третий массив состоит из 10000 элементов — 10×10×10×10.
Динамические массивы
Динамические массивы в VBA Excel, в отличие от статических, объявляются без указания размерности:
Public Massiv1() As Integer Dim Massiv2() As String |
Такие массивы используются, когда заранее неизвестна размерность, которая определяется в процессе выполнения программы. Когда нужная размерность массива становится известна, она в VBA Excel переопределяется с помощью оператора ReDim:
Public Massiv1() As Integer Dim Massiv2() As String ReDim Massiv1(1 To 20) ReDim Massiv2(3, 5, 4) |
При переопределении размерности массива вместо верхнего индекса можно использовать переменную:
Dim Massiv1() as Variant, x As Integer x = 20 ReDim Massiv1(1 To x) |
Переопределять размерность динамических массивов в процессе работы программы можно неоднократно, как по количеству измерений, так и по количеству элементов в измерении.
С помощью оператора ReDim невозможно изменить обычный массив, объявленный с заранее заданной размерностью. Попытка переопределить размерность такого массива вызовет ошибку компиляции с сообщением: Array already dimensioned (Массив уже измерен).
При переопределении размерности динамических массивов в VBA Excel теряются значения их элементов. Чтобы сохранить значения, используйте оператор Preserve:
Dim Massiv1() As String ——— операторы ——— ReDim Massiv1(5, 2, 3) ——— операторы ——— ReDim Preserve Massiv1(5, 2, 7) |
Обратите внимание!
Переопределить с оператором Preserve можно только последнюю размерность динамического массива. Это недоработка разработчиков, которая сохранилась и в VBA Excel 2016. Без оператора Preserve можно переопределить все размерности.
Максимальный размер
Размер массива – это произведение длин всех его измерений. Он представляет собой общее количество элементов, содержащихся в данный момент в массиве.
По информации с сайта разработчиков, максимальный размер массивов зависит от операционной системы и доступного объема памяти. Использование массивов, размер которых превышает объем доступной оперативной памяти компьютера, приводит к снижению скорости, поскольку системе необходимо выполнять запись данных и чтение с диска.
Использование массивов
Приведу два примера, где не обойтись без массивов.
1. Как известно, функция Split возвращает одномерный массив подстрок, извлеченных из первоначальной строки с разделителями. Эти данные присваиваются заранее объявленному строковому (As String) одномерному динамическому массиву. Размерность устанавливается автоматически в зависимости от количества подстрок.
2. Данные в массивах обрабатываются значительно быстрее, чем в ячейках рабочего листа. Построчную обработку информации в таблице Excel можно наблюдать визуально по мерцаниям экрана, если его обновление (Application.ScreenUpdating) не отключено. Чтобы ускорить работу кода, можно значения из диапазона ячеек предварительно загрузить в динамический массив с помощью оператора присваивания (=). Размерность массива установится автоматически. После обработки данных в массиве кодом VBA полученные результаты выгружаются обратно на рабочий лист Excel. Обратите внимание, что загрузить значения в диапазон ячеек рабочего листа через оператор присваивания (=) можно только из двумерного массива.
Функции Array, LBound, UBound
Функция Array
Функция Array возвращает массив элементов типа Variant из первоначального списка элементов, перечисленных через запятую. Нумерация элементов в массиве начинается с нуля. Обратиться к элементу массива можно, указав в скобках его номер (индекс).
Sub Test1() Dim a() As Variant a = Array(«text», 25, «solo», 35.62, «stop») MsgBox a(0) & vbNewLine & a(1) & vbNewLine _ & a(2) & vbNewLine & a(3) & vbNewLine & a(4) End Sub |
Скопируйте код в модуль VBA Excel и запустите его на выполнение. Информационное сообщение MsgBox покажет значения массива, извлеченные по индексу.
Функция LBound
Функция LBound возвращает значение типа Long, равное наименьшему (нижнему) доступному индексу в указанном измерении массива.
Синтаксис:
LBound (arrayname[, dimension])
- arrayname — это имя переменной массива, является обязательным аргументом;
- dimension — это номер измерения массива, необязательный аргумент, по умолчанию принимает значение 1.
Наименьший индекс по-умолчанию может быть равен 0 или 1 в зависимости от настроек оператора Option Base. Нижняя граница архива, полученного с помощью функции Array, всегда равна 0.
При объявлении переменных массивов или переопределении их размерности наименьшие индексы могут быть любыми целыми числами, в том числе отрицательными.
Функция UBound
Функция UBound возвращает значение типа Long, равное наибольшему (верхнему) доступному индексу в указанном измерении массива.
Синтаксис:
UBound( arrayname[, dimension])
- arrayname — это имя переменной массива, является обязательным аргументом;
- dimension — это номер измерения массива, необязательный аргумент, по умолчанию принимает значение 1.
Функция UBound используется вместе с функцией LBound для определения размера массива.
Sub Test2() Dim a(—2 To 53) As String MsgBox «Наименьший индекс = « & LBound(a) & _ vbNewLine & «Наибольший индекс = « & UBound(a) End Sub |
Скопируйте код в модуль VBA Excel и запустите его на выполнение. Информационное сообщение MsgBox покажет значения наименьшего и наибольшего индекса переменной массива a.
Обход массива циклом
Обход одномерного массива циклом For… Next, в котором для определения границ массива используются функции UBound и LBound:
Sub Test3() Dim a() As Variant, i As Long a = Array(«text», 25, «solo», 35.62, «stop») For i = LBound(a) To UBound(a) Debug.Print «a(« & i & «) = « & a(i) Next End Sub |
Результат работы цикла вы увидите в окне Immediate.
Очистка (обнуление) массивов
Первый способ
Очистить любой массив, статический или динамический, без использования цикла можно с помощью оператора Erase. Термин «обнуление» можно применить только к массиву числового типа.
Dim Massiv1(4, 3) As String, Massiv2() As Variant ——— операторы ——— ‘переопределяем динамический массив ReDim Massiv2(2, 5, 3) ——— операторы ——— ‘очищаем массивы Erase Massiv1 Erase Massiv2 |
Обратите внимание, что оба массива при таком способе очистки будут возвращены в исходное состояние, которое они имели сразу после объявления:
- статический Massiv1 сохранит размерность (4, 3);
- динамический Massiv2 не сохранит размерность ().
Второй способ
Динамический массив можно очистить (обнулить) без использования цикла с помощью оператора ReDim. Просто переопределите его с той же размерностью.
Dim Massiv() As Double ——— операторы ——— ‘переопределяем массив ReDim Massiv(5, 6, 8) ——— операторы ——— ‘очищаем массив ReDim Massiv(5, 6, 8) |
Добрый день. |
|
The_Prist Пользователь Сообщений: 14182 Профессиональная разработка приложений для MS Office |
Sub Arr_Initialize() Даже самый простой вопрос можно превратить в огромную проблему. Достаточно не уметь формулировать вопросы… |
Спасибо большое. Все очень понятно объяснили. |
|
The_Prist Пользователь Сообщений: 14182 Профессиональная разработка приложений для MS Office |
Впишите в ячейку А1 формулу: Вычислите её пошагово и все поймете. Даже самый простой вопрос можно превратить в огромную проблему. Достаточно не уметь формулировать вопросы… |
{quote}{login=The_Prist}{date=06.06.2010 11:30}{thema=}{post}Впишите в ячейку А1 формулу: Вычислите её пошагово и все поймете.{/post}{/quote} Вписал в ячейку B1 формулу =НЕ(НЕ(A1=0)), |
|
The_Prist Пользователь Сообщений: 14182 Профессиональная разработка приложений для MS Office |
Эх…Простой конструкцией типа avArr = 0 не получиться узнать наполнение массива — такая конструкция недопустима, сначала необходимо переопределить размерность, т.к. VBA считает, что Вы хотите присвоить массиву значение. В этом выражении: VBA сначала сравнивает массив, преобразуя его в тип Integer, независимо от данных в нем(на сами данные не влияет), не вызывая ошибку. Но все равно придется добавлять Not, чтобы было вроде как понятней(или поменять условия местами). Даже самый простой вопрос можно превратить в огромную проблему. Достаточно не уметь формулировать вопросы… |
Еще раз спасибо огромное. |
|
KuklP Пользователь Сообщений: 14868 E-mail и реквизиты в профиле. |
{quote}{login=The_Prist}{date=06.06.2010 12:22}{thema=}{post} Я сам — дурнее всякого примера! … |
The_Prist Пользователь Сообщений: 14182 Профессиональная разработка приложений для MS Office |
{quote}{login=KuklP}{date=06.06.2010 01:27}{thema=Re: }{post}{quote}{login=The_Prist}{date=06.06.2010 12:22}{thema=}{post} «В общем-то можно и так записать для достижения цели: Это же конструкция сравнения. С нулем как-то смотрится более информативно. Даже самый простой вопрос можно превратить в огромную проблему. Достаточно не уметь формулировать вопросы… |
KuklP Пользователь Сообщений: 14868 E-mail и реквизиты в профиле. |
Дим, при (Not avArr) = 0 выдаст, что массив не пустой в обоих случаях. Я сам — дурнее всякого примера! … |
KuklP Пользователь Сообщений: 14868 E-mail и реквизиты в профиле. |
Да, а Not(-1) как раз и дает 0. Я сам — дурнее всякого примера! … |
The_Prist Пользователь Сообщений: 14182 Профессиональная разработка приложений для MS Office |
{quote}{login=KuklP}{date=06.06.2010 02:07}{thema=}{post}Дим, при (Not avArr) = 0 выдаст, что массив не пустой в обоих случаях. Sub Arr_Initialize() Вот в этой процедуре получиться, что условия перепутаны. Именно про это я и писал: «Но все равно придется добавлять Not, чтобы было вроде как понятней(или поменять условия местами)» Даже самый простой вопрос можно превратить в огромную проблему. Достаточно не уметь формулировать вопросы… |
KuklP Пользователь Сообщений: 14868 E-mail и реквизиты в профиле. |
Да нет же, Дим(вот я не умею так понятно объяснять как ты) Я сам — дурнее всякого примера! … |
Юрий М Модератор Сообщений: 60575 Контакты см. в профиле |
|
The_Prist Пользователь Сообщений: 14182 Профессиональная разработка приложений для MS Office |
А, ну да. Чет я сразу не догнал. Даже самый простой вопрос можно превратить в огромную проблему. Достаточно не уметь формулировать вопросы… |
KuklP Пользователь Сообщений: 14868 E-mail и реквизиты в профиле. |
Все, сдаюсь. Я сам — дурнее всякого примера! … |
Извиняюсь, что вклиниваюсь в беседу, но у меня |
|
KuklP Пользователь Сообщений: 14868 E-mail и реквизиты в профиле. |
{quote}{login=Егор}{date=06.06.2010 02:36}{thema=}{post}Извиняюсь, что вклиниваюсь в беседу, но у меня Я сам — дурнее всякого примера! … |
The_Prist Пользователь Сообщений: 14182 Профессиональная разработка приложений для MS Office |
Вообще главная фишка такой проверки в том, что можно проверить даже неинициализированный массив. Т.к. неинициализированный массив при помощи UBound() не проверить — выдаст ошибку. Даже самый простой вопрос можно превратить в огромную проблему. Достаточно не уметь формулировать вопросы… |
{quote}{login=KuklP}{date=06.06.2010 02:43}{thema=Re: }{post}{quote}{login=Егор}{date=06.06.2010 02:36}{thema=}{post}Извиняюсь, что вклиниваюсь в беседу, но у меня мне двойное отрицание не не понравилось, а просто я не знал, что ему может быть |
|
ZVI Пользователь Сообщений: 4328 |
Массивы бывают разные. Sub Test1() Это потому, что в переменной типа Variant хранится не указатель на массив, а указатель на указатель на массив Поэтому надежнее так: Function IsArrayEmpty(x) As Boolean Sub Test2() |
В моем массиве каждый элемент это название,состоящее из 2-10 букв. |
|
KuklP Пользователь Сообщений: 14868 E-mail и реквизиты в профиле. |
{quote}{login=ZVI}{date=06.06.2010 03:34}{thema=}{post}Массивы бывают разные. Я сам — дурнее всякого примера! … |
ZVI Пользователь Сообщений: 4328 |
{quote}{login=Егор}{date=06.06.2010 04:20}{thema=}{post}В моем массиве каждый элемент это название,состоящее из 2-10 букв. |
{quote}{login=ZVI}{date=06.06.2010 04:26}{thema=}{post}{quote}{login=Егор}{date=06.06.2010 04:20}{thema=}{post}В моем массиве каждый элемент это название,состоящее из 2-10 букв. Я объявил массив Dim Arr() As Variant в процедуре обработки события в юзерформе, а затем передал его в качестве аргумента в другую процедуру, которая находится в модуле. В модуле делаю проверку на пустойнепустой. |
|
ZVI Пользователь Сообщений: 4328 |
{quote}{login=}{date=06.06.2010 05:00}{thema=Re: }{post}Я объявил массив Dim Arr() As Variant в процедуре обработки события в юзерформе, а затем передал его в качестве аргумента в другую процедуру, которая находится в модуле. В модуле делаю проверку на пустойнепустой. |
Егор Гость |
#27 06.06.2010 17:55:42 Ясно. Спасибо. |
While this is essentially just @Brad’s answer again, I thought it might be worth including a slightly modified function which will return the index of the item you’re searching for if it exists in the array. If the item is not in the array, it returns -1
instead.
The output of this can be checked just like the «in string» function, If InStr(...) > 0 Then
, so I made a little test function below it as an example.
Option Explicit
Public Function IsInArrayIndex(stringToFind As String, arr As Variant) As Long
IsInArrayIndex = -1
Dim i As Long
For i = LBound(arr, 1) To UBound(arr, 1)
If arr(i) = stringToFind Then
IsInArrayIndex = i
Exit Function
End If
Next i
End Function
Sub test()
Dim fruitArray As Variant
fruitArray = Array("orange", "apple", "banana", "berry")
Dim result As Long
result = IsInArrayIndex("apple", fruitArray)
If result >= 0 Then
Debug.Print chr(34) & fruitArray(result) & chr(34) & " exists in array at index " & result
Else
Debug.Print "does not exist in array"
End If
End Sub
Then I went a little overboard and fleshed out one for two dimensional arrays because when you generate an array based on a range it’s generally in this form.
It returns a single dimension variant array with just two values, the two indices of the array used as an input (assuming the value is found). If the value is not found, it returns an array of (-1, -1)
.
Option Explicit
Public Function IsInArray2DIndex(stringToFind As String, arr As Variant) As Variant
IsInArray2DIndex= Array(-1, -1)
Dim i As Long
Dim j As Long
For i = LBound(arr, 1) To UBound(arr, 1)
For j = LBound(arr, 2) To UBound(arr, 2)
If arr(i, j) = stringToFind Then
IsInArray2DIndex= Array(i, j)
Exit Function
End If
Next j
Next i
End Function
Here’s a picture of the data that I set up for the test, followed by the test:
Sub test2()
Dim fruitArray2D As Variant
fruitArray2D = sheets("Sheet1").Range("A1:B2").value
Dim result As Variant
result = IsInArray2DIndex("apple", fruitArray2D)
If result(0) >= 0 And result(1) >= 0 Then
Debug.Print chr(34) & fruitArray2D(result(0), result(1)) & chr(34) & " exists in array at row: " & result(0) & ", col: " & result(1)
Else
Debug.Print "does not exist in array"
End If
End Sub