Удаление элементов в массиве, если элемент имеет определенное значение VBA
у меня есть глобальный массив, prLst()
это может переменной длины. Он принимает числа как строки "1"
to Ubound(prLst)
. Однако, когда пользователь вводит "0"
, Я хочу удалить этот элемент из списка. У меня есть следующий код, написанный для выполнения этого:
count2 = 0
eachHdr = 1
totHead = UBound(prLst)
Do
If prLst(eachHdr) = "0" Then
prLst(eachHdr).Delete
count2 = count2 + 1
End If
keepTrack = totHead - count2
'MsgBox "prLst = " & prLst(eachHdr)
eachHdr = eachHdr + 1
Loop Until eachHdr > keepTrack
это не работает. Как эффективно удалить элементы в массиве prLst
если элемент "0"
?
Примечание: это часть более крупной программы, для которой описание можно найти здесь: сортировка групп строк Excel VBA макрос
7 ответов
массив-это структура с определенным размером. В vba можно использовать динамические массивы, которые можно сжимать или увеличивать с помощью ReDim, но нельзя удалять элементы посередине. Из вашего примера не ясно, как Ваш массив функционально работает или как вы определяете позицию индекса (eachHdr), но у вас в основном есть 3 варианта
(A) напишите пользовательскую функцию "Удалить" для вашего массива, например (непроверенный)
Public Sub DeleteElementAt(Byval index As Integer, Byref prLst as Variant)
Dim i As Integer
' Move all element back one position
For i = index + 1 To UBound(prLst)
prLst(i - 1) = prLst(i)
Next
' Shrink the array by one, removing the last one
ReDim Preserve prLst(Len(prLst) - 1)
End Sub
(B) просто установите "фиктивное" значение в качестве значения вместо фактического удаление элемента
If prLst(eachHdr) = "0" Then
prLst(eachHdr) = "n/a"
End If
(C) прекратите использовать массив и измените его на VBA.Коллекция. Коллекция-это (уникальная)структура пары ключ/значение, в которой вы можете свободно добавлять или удалять элементы из
Dim prLst As New Collection
Sub DelEle(Ary, SameTypeTemp, Index As Integer) '<<<<<<<<< pass only not fixed sized array (i don't know how to declare same type temp array in proceder)
Dim I As Integer, II As Integer
II = -1
If Index < LBound(Ary) And Index > UBound(Ary) Then MsgBox "Error.........."
For I = 0 To UBound(Ary)
If I <> Index Then
II = II + 1
ReDim Preserve SameTypeTemp(II)
SameTypeTemp(II) = Ary(I)
End If
Next I
ReDim Ary(UBound(SameTypeTemp))
Ary = SameTypeTemp
Erase SameTypeTemp
End Sub
Sub Test()
Dim a() As Integer, b() As Integer
ReDim a(3)
Debug.Print "InputData:"
For I = 0 To UBound(a)
a(I) = I
Debug.Print " " & a(I)
Next
DelEle a, b, 1
Debug.Print "Result:"
For I = 0 To UBound(a)
Debug.Print " " & a(I)
Next
End Sub
при создании массива, почему бы просто не пропустить 0 и сэкономить время, чтобы беспокоиться о них позже? Как упоминалось выше, массивы не подходят для удаления.
Я довольно новичок в vba & excel - только делал это около 3 месяцев - Я думал, что поделюсь своим методом де-дублирования массива здесь, поскольку этот пост кажется ему актуальным:
этот код, если часть большего приложения, которое анализирует данные канала- Трубы перечислены в листе с номером в xxxx.1, xxxx.2, гггг.1, гггг.2 .... формат. так вот почему все манипуляции со строками существуют. в основном он собирает только номер трубы только один раз, а не .2 или .Один часть.
With wbPreviousSummary.Sheets(1)
' here, we will write the edited pipe numbers to a collection - then pass the collection to an array
Dim PipeDict As New Dictionary
Dim TempArray As Variant
TempArray = .Range(.Cells(3, 2), .Cells(3, 2).End(xlDown)).Value
For ele = LBound(TempArray, 1) To UBound(TempArray, 1)
If Not PipeDict.Exists(Left(TempArray(ele, 1), Len(TempArray(ele, 1) - 2))) Then
PipeDict.Add Key:=Left(TempArray(ele, 1), Len(TempArray(ele, 1) - 2)), _
Item:=Left(TempArray(ele, 1), Len(TempArray(ele, 1) - 2))
End If
Next ele
TempArray = PipeDict.Items
For ele = LBound(TempArray) To UBound(TempArray)
MsgBox TempArray(ele)
Next ele
End With
wbPreviousSummary.Close SaveChanges:=False
Set wbPreviousSummary = Nothing 'done early so we dont have the information loaded in memory
использование кучи сообщений для отладки atm-im уверен, что вы измените его в соответствии с вашей собственной работой.
Я надеюсь, что люди найдут это полезным, С уважением Джо!--2-->
удаление элементов в массиве, если элемент имеет определенное значение VBA
чтобы удалить элементы в массиве с определенным условием, вы можете закодировать следующим образом
For i = LBound(ArrValue, 2) To UBound(ArrValue, 2)
If [Certain condition] Then
ArrValue(1, i) = "-----------------------"
End If
Next i
StrTransfer = Replace(Replace(Replace(join(Application.Index(ArrValue(), 1, 0), ","), ",-----------------------,", ",", , , vbBinaryCompare), "-----------------------,", "", , , vbBinaryCompare), ",-----------------------", "", , , vbBinaryCompare)
ResultArray = join( Strtransfer, ",")
Я часто манипулирую 1D-массивом с Join / Split но если вам нужно удалить определенное значение в нескольких измерениях, я предлагаю вам изменить этот массив на 1D-массив, как это
strTransfer = Replace(Replace(Replace(Replace(Names.Add("A", MultiDimensionArray), Chr(34), ""), "={", ""), "}", ""), ";", ",")
'somecode to edit Array like 1st code on top of this comment
'then loop through this strTransfer to get right value in right dimension
'with split function.
вот пример кода, с помощью CopyMemory
функция для выполнения задания.
предположительно "намного быстрее" (в зависимости от размера и типа массива...).
Я не автор, но я проверял это :
Sub RemoveArrayElement_Str(ByRef AryVar() As String, ByVal RemoveWhich As Long)
'// The size of the array elements
'// In the case of string arrays, they are
'// simply 32 bit pointers to BSTR's.
Dim byteLen As Byte
'// String pointers are 4 bytes
byteLen = 4
'// The copymemory operation is not necessary unless
'// we are working with an array element that is not
'// at the end of the array
If RemoveWhich < UBound(AryVar) Then
'// Copy the block of string pointers starting at
' the position after the
'// removed item back one spot.
CopyMemory ByVal VarPtr(AryVar(RemoveWhich)), ByVal _
VarPtr(AryVar(RemoveWhich + 1)), (byteLen) * _
(UBound(AryVar) - RemoveWhich)
End If
'// If we are removing the last array element
'// just deinitialize the array
'// otherwise chop the array down by one.
If UBound(AryVar) = LBound(AryVar) Then
Erase AryVar
Else
ReDim Preserve AryVar(LBound(AryVar) To UBound(AryVar) - 1)
End If
End Sub
- цикл через массив (вариант) добавление каждого элемента и некоторого делителя в строку, если он не соответствует тому, который вы хотите удалить - Тогда разделите строку на разделитель
tmpString=""
For Each arrElem in GlobalArray
If CStr(arrElem) = "removeThis" Then
GoTo SkipElem
Else
tmpString =tmpString & ":-:" & CStr(arrElem)
End If
SkipElem:
Next
GlobalArray = Split(tmpString, ":-:")
очевидно, что использование строк создает некоторые ограничения, например, нужно быть уверенным в информации, уже в массиве, и как этот код делает первый элемент массива пустой, но он делает то, что мне нужно, и с немного большей работой он может быть более универсальным.