Удаление элемента из динамического массива

Программирование на Visual Basic, главный форум. Обсуждение тем программирования на VB 1—6.
Даже если вы плохо разбираетесь в VB и программировании вообще — тут вам помогут. В разумных пределах, конечно.
Правила форума
Темы, в которых будет сначала написано «что нужно сделать», а затем просьба «помогите», будут закрыты.
Читайте требования к создаваемым темам.
ZOD
Обычный пользователь
Обычный пользователь
 
Сообщения: 75
Зарегистрирован: 24.03.2004 (Ср) 19:54
Откуда: Barnaul

Удаление элемента из динамического массива

Сообщение ZOD » 07.07.2004 (Ср) 19:44

Как удалить элемент динамического массива со сдвигом вверх? При этом данные должны быть сохранены.

GSerg
Шаман
Шаман
 
Сообщения: 14286
Зарегистрирован: 14.12.2002 (Сб) 5:25
Откуда: Магадан

Сообщение GSerg » 07.07.2004 (Ср) 20:46

Сначала CopyMemory, а потом Redim Preserve.
Как только вы переберёте все варианты решения и не найдёте нужного, тут же обнаружится решение, простое и очевидное для всех, кроме вас

ZOD
Обычный пользователь
Обычный пользователь
 
Сообщения: 75
Зарегистрирован: 24.03.2004 (Ср) 19:54
Откуда: Barnaul

Сообщение ZOD » 08.07.2004 (Чт) 7:35

А нельзя ли поконкретнее, как использовать CopyMemory, а то я в этом деле не очень разбираюсь.

pitbull
Постоялец
Постоялец
 
Сообщения: 314
Зарегистрирован: 25.06.2004 (Пт) 15:37
Откуда: Кемерово

Сообщение pitbull » 08.07.2004 (Чт) 11:55

Берешь и обнуляешь (делаешь Empty) ненужный элемент. Потом в цикле, начиная с порядкового номера этого эл-та в цикле делаешь следующее
a(12)=0
for i=12 to 34
a(i)=a(i+1)
a(i+1)=0
next i
вот, кажись, все :D

san*
Продвинутый пользователь
Продвинутый пользователь
 
Сообщения: 115
Зарегистрирован: 17.06.2004 (Чт) 17:57
Откуда: Киев

Сообщение san* » 08.07.2004 (Чт) 16:06

pitbull писал(а):Берешь и обнуляешь (делаешь Empty) ненужный элемент. Потом в цикле, начиная с порядкового номера этого эл-та в цикле делаешь следующее
a(12)=0
for i=12 to 34
a(i)=a(i+1)
a(i+1)=0
next i
вот, кажись, все :D

Можно было б обойтись и без обнуления, а в конце написать
Redim Preserve a(1 to 34) ' если конечно елементов до этого было 1 to 35

alibek
Большой Человек
Большой Человек
 
Сообщения: 14205
Зарегистрирован: 19.04.2002 (Пт) 11:40
Откуда: Russia

Сообщение alibek » 08.07.2004 (Чт) 17:22

Если массив имеет числовой тип (Integer, Long, Single, Double, Currency, Date, Boolean, Byte), то как советовал GSerg (сделать CopyMemory из D(i) в D(i-1), а затем ReDim Preserve). А если массив строковый или пользовательского типа, то только поштучным перетаскиванием элементов массива (a-la pitbull)
Lasciate ogni speranza, voi ch'entrate.

Approximator
Постоялец
Постоялец
 
Сообщения: 572
Зарегистрирован: 26.06.2004 (Сб) 3:10

Сообщение Approximator » 09.07.2004 (Пт) 2:39

ZOD писал(а):А нельзя ли поконкретнее, как использовать CopyMemory, а то я в этом деле не очень разбираюсь.

Приблизительно так (твой уже ЗАПОЛНЕННЫЙ ОДНОМЕРНЫЙ массив называется Arr(); а переменная TrashIndex обозначает номер элементра, от которого ты хочешь избавиться):

Код: Выделить всё
Public Declare Sub CopyMem Lib "kernel32" Alias "RtlMoveMemory" _
(ByVal pDst As Long, ByVal pSrc As Long, ByVal ByteLen As Long)

Public Type SAFEARRAYBOUND
DSize As Long
DLbound As Long
End Type

Public Type SAFEARRAY
cDims As Integer
fFeat As Integer
ESize As Long
cLocks As Long
pvData As Long
Bounds As SAFEARRAYBOUND
End Type

Public Function AnyPtr(ByRef vVar As Variant) As Long
CopyMem VarPtr(AnyPtr), VarPtr(vVar) + 1, 1
If AnyPtr = 64 Or AnyPtr = 96 Then CopyMem VarPtr(AnyPtr), VarPtr(vVar) + 8, 4
End Function

Public Sub MyReDim(ByRef vArr as Variant, ByRef vTrashIndex as Long)
Dim lESize as Byte
CopyMem VarPtr(lASA), VarPtr(vArr) + 1, 1
If lASA = 96 Then
  CopyMem VarPtr(lESize), VarPtr(vArr), 1
  Select Case  lESize
   Case 17
    lESize=1
   Case 2
    lESize=2
   Case 3, 4, 8
    lESize=4
   Case 5-7
    lESize=8
  End Select
  CopyMem VarPtr(vArr(vTrashIndex-LBound(vArr))), VarPtr(vArr(vTrashIndex-LBound(vArr))+1), lESize*(UBound(vArr)-vTrashIndex)
  ReDim Preserve vArr(LBound(vArr) to (UBound(vArr)-lBound(vArr)))
Else
  Exit Sub
End IF
End Sub

Public Sub MyReDimEx(ByRef vArr as Variant, ByRef vTrashIndex as Long)
Dim lSF as SAFEARRAY, lASA as Long
CopyMem VarPtr(lASA), VarPtr(vVar) + 1, 1
If lASA = 96 Then
  CopyMem VarPtr(lASA), VarPtr(vVar) + 8, 4
  CopyMem VarPtr(lSA), lSA, 24
  With lSA.Bounds
   CopyMem lSA.pvData+lSA.ESize*(vTrashIndex-.DLBound), lSA.pvData+lSA.ESize*(vTrashIndex-.DLBound+1), lSA.ESize*(.DSize-vTrashIndex+.DLBound-1)
   ReDim Preserve vArr(.DLBound to (.DSize-1))
  End With
Else
  Exit Sub
End IF
Enf Sub

'Теперь в зависимости от обстоятельств
MyReDim Arr, TrashIndex
'или
MyReDimEx Arr, TrashIndex


alibek писал(а):Если массив имеет числовой тип (Integer, Long, Single, Double, Currency, Date, Boolean, Byte), то как советовал GSerg (сделать CopyMemory из D(i) в D(i-1), а затем ReDim Preserve). А если массив строковый или пользовательского типа, то только поштучным перетаскиванием элементов массива (a-la pitbull)

Ну, на мой взгляд, даже в случае строкового или пользовательского динамического массива не стоит пользоваться примером, предложенным pitbull. Для строк подойдёт и MyReDim, а в кач-ве универсальной функции MyReDimEx. И дело здесь вот в чём.
Что динамические массивы строк, что динамические массивы данных любого пользовательского типа прописываются следующим образом: "в заголовке" прописывается массив Long, который содержит VarPtr'ы на каждый элемент массива. Так что по-сути можно работать, как с динамическим массивом типа Long. Хотя, в MyReDimEx универсальности ради я определяю размер элемента в массиве указателей...
С уважением, Approximator.

pitbull
Постоялец
Постоялец
 
Сообщения: 314
Зарегистрирован: 25.06.2004 (Пт) 15:37
Откуда: Кемерово

Сообщение pitbull » 09.07.2004 (Пт) 5:18

Вот это прикольно :) Я ведь и писал пример в надежде на то, что кто-то знает как делать это все через CopyMemory, и увидев мой пример решит показать свой. Ну вот теперь умней малек стал. :D :D :D

Approximator
Постоялец
Постоялец
 
Сообщения: 572
Зарегистрирован: 26.06.2004 (Сб) 3:10

Сообщение Approximator » 09.07.2004 (Пт) 7:09

pitbull писал(а):Вот это прикольно :) Я ведь и писал пример в надежде на то, что кто-то знает как делать это все через CopyMemory, и увидев мой пример решит показать свой. Ну вот теперь умней малек стал. :D :D :D

На здоровье.
С уважением, Approximator.

Approximator
Постоялец
Постоялец
 
Сообщения: 572
Зарегистрирован: 26.06.2004 (Сб) 3:10

Сообщение Approximator » 09.07.2004 (Пт) 7:16

Кстати, настоятельно не рекомендую этот метод использовать для фиксированных массивов.
С уважением, Approximator.

kif
Постоялец
Постоялец
 
Сообщения: 736
Зарегистрирован: 10.12.2001 (Пн) 18:06
Откуда: Украина, Одесса

Сообщение kif » 09.07.2004 (Пт) 10:23

Если массив пользовательского типа, то лучше добавить еще признак удаления и использовать его. Быстрее будет, чем реально удалить элемент. Особенно для массивов большого объема.
Братья и сестры, что вы делаете???
Ведь вы же братья и сестры.

ZOD
Обычный пользователь
Обычный пользователь
 
Сообщения: 75
Зарегистрирован: 24.03.2004 (Ср) 19:54
Откуда: Barnaul

Сообщение ZOD » 09.07.2004 (Пт) 11:55

Всем большое спасибо за ответы!

MOV
Постоялец
Постоялец
 
Сообщения: 414
Зарегистрирован: 13.03.2004 (Сб) 15:13
Откуда: Санкт-Петербург

Сообщение MOV » 09.07.2004 (Пт) 22:33

Я как всегда опздал :? . А все-таки. Почему не использовать объект коллекцию, там ведь удаление происходит просто по индексу, насколько помню (по аналогии с элементами листбокса) обычным Remove, помоему. Или Collection ест больше памяти и едленне пашет? (я думаю и то и другое, зато удобнее немного :shock: ).

Approximator
Постоялец
Постоялец
 
Сообщения: 572
Зарегистрирован: 26.06.2004 (Сб) 3:10

Сообщение Approximator » 10.07.2004 (Сб) 2:04

kif писал(а):Если массив пользовательского типа, то лучше добавить еще признак удаления и использовать его. Быстрее будет, чем реально удалить элемент. Особенно для массивов большого объема.


Ну, на самом деле вряд ли... Я себе не представляю, метода, который мог бы работать быстрее. Другое дело, когда создаёшь массив a la Collection (то есть собственную обёртку для класса, но и в этом случае код не будет отличаться ничем особенным...)

MOV писал(а):А все-таки. Почему не использовать объект коллекцию, там ведь удаление происходит просто по индексу, насколько помню (по аналогии с элементами листбокса) обычным Remove, помоему. Или Collection ест больше памяти и едленне пашет? (я думаю и то и другое, зато удобнее немного ).

Медленнее. Связано это с тем, что там всё равно заложена "порочная" итерация на манер, как у pitbull'я
С уважением, Approximator.

pitbull
Постоялец
Постоялец
 
Сообщения: 314
Зарегистрирован: 25.06.2004 (Пт) 15:37
Откуда: Кемерово

Сообщение pitbull » 12.07.2004 (Пн) 8:29

ДА ладно. Интеррация не такая уж и порочная штука. В "маленьких" (не критичных ко времени исполнения) программах с маленькими массивам работает и очень ничиго и по времени не сильно уступает. Может получиться, что основной код проги будет меньше, чем код удаления эл-та. И стоит ли заморачиваться.
Но в с большими массивами, безусловно, лучше делать так, как посоветовал Approximator.

Approximator
Постоялец
Постоялец
 
Сообщения: 572
Зарегистрирован: 26.06.2004 (Сб) 3:10

Сообщение Approximator » 13.07.2004 (Вт) 3:48

:) Сам факт того, что мы все здесь в основном программируем на VB показыает то, что нам всем не чужды компромиссы... :)
С уважением, Approximator.

pitbull
Постоялец
Постоялец
 
Сообщения: 314
Зарегистрирован: 25.06.2004 (Пт) 15:37
Откуда: Кемерово

Сообщение pitbull » 13.07.2004 (Вт) 10:15

ДА. Ты снова абсолютно прав!!!


Вернуться в Visual Basic 1–6

Кто сейчас на конференции

Сейчас этот форум просматривают: Google-бот, Yandex-бот и гости: 20

    TopList