Способ первый. Тупой, без сортировки. Работает за o(n^2) колва элементов.
Public Sub RemoveCopies(ByRef vArr() As String, _
ByRef Output() As String)
Dim RemMarks() As Boolean 'True если элемент надо удалить
Dim i As Long, j As Long
Dim n As Long
ReDim RemMarks(LBound(vArr) To UBound(vArr))
ReDim Output(LBound(vArr) To UBound(vArr))
n = LBound(vArr)
For i = LBound(vArr) To UBound(vArr)
If Not RemMarks(i) Then
'Добавить этот элемент
Output(n) = vArr(n)
n = n + 1
'Пометить оставшиеся элементы, которые равны vArr(i), для
удаления
For j = i + 1 To UBound(vArr)
If Not RemMarks(i) Then
If vArr(j) = vArr(i) Then
RemMarks(j) = True
End If
End If
Next j
End If
Next i
ReDim Preserve Output(LBound(vArr) To n - 1)
End Sub
Сводится к o(n), если в исходном массиве очень много совпадающих элементов.
Выводит результат в массив Output в том порядке, в котором они идут в
исходном массиве (устранив дубликаты). Исходный массив оставляет нетронутым.
Второй способ. Отсортировать, затем пройтись по массиву. Учитывая при этом,
что надо брать очередной элемент только если он отличен от последнего
добавленного.
Sub RemoveCopies2(ByRef vArr() As String, ByRef Output() As String)
QSort vArr, LBound(vArr), UBound(vArr)
Dim i As Long
Dim n As Long
ReDim Output(LBound(vArr) To UBound(vArr))
i = LBound(vArr)
Output(i) = vArr(i)
n = i + 1
For i = LBound(vArr) + 1 To UBound(vArr)
If Not vArr(i) = Output(n - 1) Then
Output(n) = vArr(i)
n = n + 1
End If
Next i
ReDim Preserve Output(LBound(vArr) To n - 1)
End Sub
Public Sub QSort(ByRef vArr() As String, _
ByVal lngLeft As Long, _
ByVal lngRight As Long)
Dim i As Long
Dim j As Long
Dim TestVal As String
Dim lngMid As Long
'If lngLeft = dhcMissing Then lngLeft = LBound(varr)
'If lngRight = dhcMissing Then lngRight = UBound(varr)
If lngLeft < lngRight Then
lngMid = (lngLeft + lngRight) \ 2
TestVal = vArr(lngMid)
i = lngLeft
j = lngRight
Do
Do While (vArr(i) < TestVal)
i = i + 1
Loop
Do While (vArr(j) > TestVal)
j = j - 1
Loop
If i <= j Then
SwapStrings vArr(i), vArr(j)
i = i + 1
j = j - 1
End If
Loop Until i > j
' To optimize the sort, always sort the
' smallest segment first.
If j <= lngMid Then
Call QSort(vArr, lngLeft, j)
Call QSort(vArr, i, lngRight)
Else
Call QSort(vArr, i, lngRight)
Call QSort(vArr, lngLeft, j)
End If
End If
End Sub
Private Sub SwapStrings(ByRef St1 As String, ByRef St2 As String)
Dim tmp As String
tmp = St1
St1 = St2
St2 = tmp
End Sub
Работает за время o(n*log(n)) (время работы сортировки) почти не зависимо от
начальных данных (хотя может и если массив предварительно отсортирован,
будет работать быстрее). Бяка в том, что исходный массив она не сохраняет, а
сортирует его. А в Output выдает отсортированный без дубликатов.
Примечание. Оценка времени o(...) означает, что время будет зависеть от
количества элементов пропорционально ... при больших количествах элементов.
Например, оценка o(n) означает, что время работы растет пропорционально
количеству элементов, когда n большое.
PS. Протестил эти функции на тривиальном примере. Глюки могут быть - не
гарантирую.
PPS. Знаю, что и данную реализацию QSort, и мои импровизации по удалению
элементов можно ускорить. Но не стал этого делать. Влом.
В том и проблема , что если я буду писать
Arr() as String , то у мя тогда в других местах начинают ошибки выпрыгивать .
Мож кто-нить хоть алгоритм какой попроще подскажет . А то я уже на одном месте дофига времени сижу . Мне надо прогу быстрее заканчивать
Дело не в алгоритме. Он может быть любой.
Попробуй сделать так: объяви свой массив глобальным, чтобы из любой процедуры его было видно, и не надо было его передавать как параметр между процедурами.
Public MyArr() As String
А если ты сделаешь локальный массив в какой-то процедуре (он будет располагаться в стеке), то никто тебе естественно не позволит из другой процедуры менять стековый фрейм при ReDim (если действительно на стеке создаётся)
У меня как бы модуль чем-то похожий на listbox. Он хранит в себе массив со строками . Моя прога кладет данные в массив по одному и получает по 1 .
Мне нужно чтоб моя прога положила инфу в массив , вызвала функцию удаления дубликатов , затем забираем инфу уже в саму прогу . Проблема в том , что у меня в модуле в General Dim list (4096) as string . А если я напишу Dim list () as String , то в функциях добавления у меня начинают вылезать ошибки . В принципе я могу выложить весть код модуля ...
Dim list(4096) As String
Dim index As Integer
Public lastindex As Integer
Public ordMode As Integer
Public fSortHiToLo As Integer
Public Function AddItem(str$)
list(lastindex + 1) = str
lastindex = lastindex + 1
End Function
Public Function Clear()
lastindex = -1
Do Until list(index) = ""
list(index) = ""
index = index + 1
Loop
index = 0
End Function
Public Function Text(index)
Text = list(index)
End Function
' Вывод всех строк массива
Public Function Debuging()
BDform.Debuging.Clear
index = 0
Do Until list(index) = ""
BDform.Debuging.AddItem list(index)
index = index + 1
Loop
index = 0
End Function
Public Sub DelDuplicate()
' Сортировка
Call SortArray(0, lastindex)
q = 0
' удаляем дубликаты
End Sub
Sub SortArray(iFirst As Integer, iLast As Integer)
 im vSplit As Variant
If iFirst < iLast Then
If iLast - iFirst = 1 Then
If SortCompare(list(iFirst), list(iLast)) > 0 Then
SortSwap list(iFirst), list(iLast)
End If
Else
 im i As Integer, j As Integer, iRand As Integer
iRand = GetRandom(iFirst, iLast)
SortSwap list(iLast), list(iRand)
vSplit = list(iLast)
 o
i = iFirst: j = iLast
 o While (i < j) And _
SortCompare(list(i), vSplit) <= 0
i = i + 1
Loop
 o While (j > i) And _
SortCompare(list(j), vSplit) >= 0
j = j - 1
Loop
If i < j Then
SortSwap list(i), list(j)
End If
Loop While i < j
SortSwap list(i), list(iLast)
If (i - iFirst) < (iLast - i) Then
SortArray iFirst, i - 1
SortArray i + 1, iLast
Else
SortArray i + 1, iLast
SortArray iFirst, i - 1
End If
End If
End If
End Sub
Public Function SortCompare(v1 As Variant, v2 As Variant) As Integer
If TypeName(v1) <> "String" Then ordMode = ordSortVal
 im i As Integer
Select Case ordMode
Case ordSortVal
If v1 < v2 Then
i = -1
ElseIf v1 = v2 Then
i = 0
Else
i = 1
End If
Case ordSortText
i = StrComp(v1, v2, 1)
Case ordSortBin
i = StrComp(v1, v2, 0)
Case ordSortLen
If Len(v1) = Len(v2) Then
If v1 = v2 Then
i = 0
ElseIf v1 < v2 Then
i = -1
Else
i = 1
End If
ElseIf Len(v1) < Len(v2) Then
i = -1
Else
i = 1
End If
End Select
If fSortHiToLo Then i = -i
SortCompare = i
End Function
Function GetRandom(iLo As Integer, iHi As Integer) As Integer
GetRandom = Int(iLo + (Rnd * (iHi - iLo + 1)))
End Function
Sub SortSwap(v1 As Variant, v2 As Variant)
 im vT As Variant
vT = v1
v1 = v2
v2 = vT
End Sub
Несколько советов, если хочешь:
Первая строка должна быть Option Explicit. Возьми это за правило.
Не объявляй переменные и функции как variant без крайней необходимости. Это тормоза и куча ошибок.
Объявляй As String, As Long и т.д.
Не используй имена ф-ций и переменных типа Text или list. Это дефолтные свойства объектов типа TextBox и ListBox. Сам же и будешь потом на эти грабли наступать.
Вот модуль для добавления элементов, удаления дубликатов, уничтожения массива, получения строки из массива, отображения содержимого всего массива:
Option Explicit
Public MyArray() As String
Public Function AddItem(item As String) 'добавление элемента в массив
Dim ub As Long
Err.Number = 0
On Error Resume Next
ub = UBound(MyArray())
If Err.Number = 9 Then
ReDim Preserve MyArray(0 To 0)
Else
ReDim Preserve MyArray(0 To UBound(MyArray()) + 1)
End If
MyArray(UBound(MyArray())) = item
Debug.Print UBound(MyArray())
End Function
Public Function Clear() 'удаление массива
Erase MyArray
End Function
Public Function GetArrayString(index As Long) As String 'получение элемента из массива
GetArrayString = MyArray(index)
End Function
Public Function ShowArray() 'показать массив
Dim ub As Long, i As Long
Err.Number = 0
On Error Resume Next
ub = UBound(MyArray())
If Err.Number = 9 Then
Debug.Print "Array is empty. Nothing to show"
Else
For i = 0 To UBound(MyArray())
Debug.Print MyArray(i)
Next i
End If
End Function
Public Sub DeleteDuplicate() 'удалить дубликаты
Dim temp_arr() As String
Dim k As Long, i As Long
Dim ub As Long
Err.Number = 0
On Error Resume Next
ub = UBound(MyArray())
If Err.Number = 9 Then Exit Sub
If ub = 0 Then Exit Sub
recur_sort MyArray(), 0, UBound(MyArray)
On Error GoTo end_arr
ReDim temp_arr(LBound(MyArray()) To UBound(MyArray()))
k = LBound(MyArray())
For i = LBound(MyArray()) To UBound(MyArray()) - 1
temp_arr(k) = MyArray(i): k = k + 1
Do While MyArray(i) = MyArray(i + 1)
i = i + 1
Loop
Next i
end_arr:
If MyArray(UBound(MyArray())) <> temp_arr(k - 1) Then
temp_arr(k) = MyArray(UBound(MyArray()))
End If
ReDim Preserve temp_arr(LBound(MyArray()) To k)
For i = LBound(temp_arr()) To UBound(temp_arr())
MyArray(i) = temp_arr(i)
Next i
ReDim Preserve MyArray(LBound(temp_arr()) To UBound(temp_arr()))
End Sub
Private Function partition(a() As String, Low As Long, High As Long) As Long
Dim p As Long, pivot As String, t As String
Dim i As Long, j As Long
p = Low + ((High - Low) \ 2)
pivot = a(p)
a(p) = a(Low)
i = Low + 1
j = High
Do While True
Do While (i < j And (pivot > a(i))): i = i + 1: Loop
Do While (j >= i And (a(j) > pivot)): j = j - 1: Loop
If (i >= j) Then Exit Do
t = a(i)
a(i) = a(j)
a(j) = t
j = j - 1
i = i + 1
Loop
a(Low) = a(j)
a(j) = pivot
partition = j
End Function
Private Sub recur_sort(SortArray() As String, Low As Long, High As Long)
Dim m As Long
Do While Low < High
m = partition(SortArray(), Low, High)
If (m - Low <= High - m) Then
recur_sort SortArray(), Low, m - 1
Low = m + 1
Else
recur_sort SortArray(), m + 1, High
High = m - 1
End If
Loop
Причем фокус в том что когда у меня 1 форма (часть моей проги) и твой модуль - все ОК . Как только я модуль и форму запускаю в одном проекте со всем остальным - начинает вылезать эта самая ошибка