VBA - Remove duplicate values of an array - arrays

I want to remove the duplicated values of an sorted array.
Here is the code to sort the values in ascending order.
Dim k As Integer
Dim j As Integer
Dim sortedArray As Variant
Dim sorting As Boolean
If sorting = True Then
For j = LBound(concentrationArray) To UBound(concentrationArray)
For k = j + 1 To UBound(concentrationArray)
If concentrationArray(j) < concentrationArray(k) Then
sortedArray = concentrationArray(j)
concentrationArray(j) = concentrationArray(k)
concentrationArray(k) = sortedArray
End If
Next k
Next j
ElseIf sorting = False Then
For j = LBound(concentrationArray) To UBound(concentrationArray)
For k = j + 1 To UBound(concentrationArray)
If concentrationArray(j) > concentrationArray(k) Then
sortedArray = concentrationArray(k)
concentrationArray(k) = concentrationArray(j)
concentrationArray(j) = sortedArray
End If
Next k
Next j
End If
However, from these sorted array, they may contain repeated values which I want to remove them.
For j = LBound(concentrationArray) To UBound(concentrationArray)
For k = j + 1 To UBound(concentrationArray)
If concentrationArray(j) <> concentrationArray(k) Then
sortedArray = concentrationArray(j)
concentrationArray(j) = concentrationArray(k)
concentrationArray(k) = sortedArray
ElseIf concentrationArray(j) = concentrationArray(k) Then
sortedArray = concentrationArray(j)
concentrationArray(j) = concentrationArray(k + 1)
ReDim concentrationArray(LBound(concentrationArray) To UBound(concentrationArray) - 1) As Variant
concentrationArray(k) = sortedArray
End If
Next k
Next j
I don't understand why this returns error.
Can anyone help?
Thanks in advance
--------------------------SOLVED--------------------------
Here it is another way to make it work:
j = LBound(concentrationArray)
While j < UBound(concentrationArray)
If concentrationArray(j) = concentrationArray(j+1) Then
Call DeleteElementArray(j, concentrationArray)
End If
j = j + 1
Wend
Public Sub DeleteElementArray(ByVal arrIndex as Integer, ByRef myArr as Variant)
Dim p as Long
For p = arrIndex+1 To Ubound(myArr)
myArr(p-1) = myArr(p)
Next p

Use this simple trick to make a 1D array unique:
Function Unique(aFirstArray() As Variant)
'Collections can be unique, as long as you use the second Key argument when adding items.
'Key values must always be unique, and adding an item with an existing Key raises an error:
'hence the On Error Resume Next
Dim coll As New Collection, a
Dim tempArray() As Variant 'aFirstArray(),
Dim i As Long
' aFirstArray() = Array("Banana", "Apple", "Orange", "Tomato", "Apple", _
' "Lemon", "Lime", "Lime", "Apple")
On Error Resume Next
For Each a In aFirstArray
'Debug.Print a
coll.Add a, a
Next
ReDim aFirstArray(coll.count)
For i = 1 To coll.count
'Cells(i, 1) = coll(i)
aFirstArray(i) = coll(i)
Next
End Function

As your data is already sorted you could also use an ArrayList object and then extract all items in one go with .toArray. You can use .Contains method to add only unique items.
Option Explicit
Public Sub DeDuplicateArray()
Dim sortedArray(), i As Long, sList As Object, arr()
sortedArray = Array(0, 0, 1, 2, 2, 3)
Set sList = CreateObject("System.Collections.ArrayList")
For i = LBound(sortedArray) To UBound(sortedArray)
If Not sList.contains(sortedArray(i)) Then sList.Add sortedArray(i)
Next
arr = sList.toArray
Debug.Print UBound(arr)
End Sub
If data wasn't sorted you could add to a SortedList object, using a test of .Contains to exclude duplicates.
Option Explicit
Public Sub DeDuplicateArray()
Dim sortedArray(), i As Long, sList As Object
sortedArray = Array(0, 0, 1, 2, 2, 3)
Set sList = CreateObject("System.Collections.SortedList")
For i = LBound(sortedArray) To UBound(sortedArray)
If Not sList.contains(sortedArray(i)) Then sList.Add sortedArray(i), vbNullString
Next
Debug.Print sList.Count
End Sub

try this code please:
Option Explicit
Sub ifDublicate()
Dim i, lRow As Integer
Dim actuellCell, cellInArray As Variant
Dim countValues, deleted As Double
'Dim arr ()
'lRow = ActiveSheet.Range("A" & Range("A:A").Rows.Count).End(xlUp).Row
'arr = Range("A1:A" & lRow)
Dim arr(10) As Variant ' or array from worksheet
arr(0) = "Apple"
arr(1) = "Orange"
arr(2) = "Apple"
arr(3) = "Apple"
arr(4) = "beans"
arr(5) = "beans"
arr(6) = "Orange"
arr(7) = "Orange"
arr(8) = "sandwitch"
arr(9) = "coffee"
arr(10) = "nuts"
For i = 0 To UBound(arr)
actuellCell = arr(i)
If InStr(cellInArray, actuellCell) > 0 Then
' ActiveSheet.Cells(i, 2) = "Already Exists"
deleted = deleted + 1
Else
cellInArray = CStr(cellInArray) & "," & CStr(actuellCell)
countValues = countValues + 1
If Left(cellInArray, 1) = "," Then
cellInArray = Right(cellInArray, Len(cellInArray) - 1)
End If
End If
Next i
MsgBox "Array after remove duplicate: " & cellInArray & vbNewLine & _
"Count Values without duplicate: " & countValues & vbNewLine & _
"deleted: " & deleted & vbNewLine & _
"last value: " & actuellCell
End Sub

Related

Excel VBA ARRAY Loop to Database

I have a huge challenge which is: Search a massive database, a list of products. This database is divided into 3 dif. sheets. The result should be stored on a 4th sheet and organized by date in columns and summarized by quantity. Each database sheet has the same format (Product / Date / Quantity).
I was told that a vba array would work perfectly.
Any help will be very appreciated.
Thanksenter image description here
Pivot (Multiple Worksheets)
The Code
Option Explicit
Sub PivotMulti()
' Data
Const srcList As String = "Sheet1,Sheet2,Sheet3"
Const srcFirst As String = "A2"
' Destination
Const dstName As String = "SUMMARY"
Const dstFirst As String = "B2"
Const TitlesList As String = "Source Data,Product"
' Other
Const Delimiter As String = "###"
' Workbook
Dim wb As Workbook: Set wb = ThisWorkbook
' Define Data Ranges and write their values to arrays of Data Array.
Dim srcNames() As String: srcNames = Split(srcList, ",")
Dim sUpper As Long: sUpper = UBound(srcNames)
Dim Data As Variant: ReDim Data(0 To sUpper)
Dim rng As Range
Dim dCount As Long
Dim n As Long
For n = 0 To sUpper
With wb.Worksheets(srcNames(n)).Range(srcFirst)
Set rng = .Resize(.Worksheet.Rows.Count - .Row + 1).Find( _
What:="*", _
LookIn:=xlFormulas, _
SearchDirection:=xlPrevious)
Data(n) = .Resize(rng.Row - .Row + 1, 3).Value
dCount = dCount + UBound(Data(n))
End With
Next n
' Define data structures.
Dim dictS As Object: Set dictS = CreateObject("Scripting.Dictionary")
dictS.CompareMode = vbTextCompare
Dim dictD As Object: Set dictD = CreateObject("Scripting.Dictionary")
Dim arlS As Object: Set arlS = CreateObject("System.Collections.ArrayList")
Dim arlD As Object: Set arlD = CreateObject("System.Collections.ArrayList")
' Declare additional variables.
Dim CurrString As String
Dim CurrDate As Date
Dim i As Long
Dim j As Long
Dim k As Long
' Write values from Data Array to dictionaries and array lists
' (dictianaries for 'unique' and 'sum', array lists for 'sort').
For n = 0 To sUpper
For i = 1 To UBound(Data(n), 1)
CurrDate = Data(n)(i, 2)
If Not dictD.Exists(CurrDate) Then
arlD.Add CurrDate
dictD(CurrDate) = Empty
End If
CurrString = Data(n)(i, 1) & Delimiter & srcNames(n) & Delimiter _
& Format(CurrDate, "yyyymmdd") & Delimiter & CurrDate
dictS(CurrString) = dictS(CurrString) + Data(n)(i, 3)
Next i
Next n
Set dictD = Nothing
Erase Data
Erase srcNames
arlD.Sort
Dim Key As Variant
For Each Key In dictS.Keys
arlS.Add Key & Delimiter & dictS(Key)
Next Key
Set dictS = Nothing
arlS.Sort
' Define Result Array.
Dim rrCount As Long: rrCount = 1 + arlS.Count
Dim rcCount As Long: rcCount = 2 + arlD.Count
Dim Result As Variant: ReDim Result(1 To rrCount, 1 To rcCount)
' Write headers.
Dim Titles() As String: Titles = Split(TitlesList, ",")
Result(1, 1) = Titles(0)
Result(1, 2) = Titles(1)
Erase Titles
j = 2
For Each Key In arlD
j = j + 1
Result(1, j) = Key
Next Key
' Write 'body'.
Dim Current() As String
Dim Previous(0 To 1) As String
i = 1
For Each Key In arlS
i = i + 1
Current = Split(Key, Delimiter)
If Current(0) <> Previous(0) Or Current(1) <> Previous(1) Then
For j = 1 To 2
Result(i, j) = Current(2 - j)
Next j
Else
i = i - 1
End If
CurrDate = CDate(Current(3))
Result(i, 3 + arlD.IndexOf(CurrDate, 0)) = CDbl(Current(4))
Previous(0) = Current(0)
Previous(1) = Current(1)
Next Key
Set arlD = Nothing
Set arlS = Nothing
' Write values from Result Array to Destination Range.
With wb.Worksheets(dstName).Range(dstFirst).Resize(, rcCount)
Application.ScreenUpdating = False
' Worksheet
.Worksheet.Cells.Clear
' Range
With .Resize(i)
.Value = Result ' Write.
With .Borders
.LineStyle = xlContinuous
.Weight = xlThin
End With
End With
' Headers
.Font.Bold = True
.Interior.Color = vbYellow
' Body
With .Resize(i - 1).Offset(1)
'.Font.Color = vbRed
End With
' Columns
.Columns.AutoFit
Application.ScreenUpdating = True
End With
MsgBox "Data transferred.", vbInformation, "Success"
End Sub

Storing cell addresses into an array in vba while using a loop

I am trying to work through a code that utilizes a system to check two different worksheets by using a for loop and highlight the differences/edits made in the second sheet ("Version 2") onto the first sheet ("Original"). I have a feeling that I need to utilize an array but I'm not advanced enough where I know how to store the values and then later write them onto another sheet (down below).
I've gotten the code so that it highlights all the relevant cells, but now I'm trying to output it into a report (on another sheet called 'Logged Changes') which will summarize all the cell addresses where edits were made. Please forgive all the variables as this is from an old code set where variables are not explicitly defined:
Private Sub CompareBasic()
Dim actSheet As Range
Dim k As Integer
Dim o As Long
Dim p As Long
Dim i As Integer
Dim change As Integer
o = Worksheets("Original").Cells(2, Columns.Count).End(xlToLeft).Column
p = Worksheets("Original").Range("A" & Rows.Count).End(xlUp).Row
change = 0
Sheets("Original").Select
For i = 2 To p
For k = 1 To o
If IsNumeric(Worksheets("Original").Cells(i, k).Value) = True Then
If Worksheets("Original").Cells(i, k).Value <> Worksheets("Version 2").Cells(i, k).Value Then
Worksheets("Original").Cells(i, k).Interior.ColorIndex = 37
change = change + 1
End If
Else
If StrComp(Worksheets("Original").Cells(i, k), Worksheets("Version 2").Cells(i, k), vbBinaryCompare) <> 0 Then
Worksheets("Original").Cells(i, k).Interior.ColorIndex = 37
change = change + 1
End If
End If
Next k
Next i
Unload Me
MsgBox "Number of cells edited counted: " & change, vbOKOnly + vbExclamation, "Summary"
b = Empty
answer = MsgBox("Do you want to run the Report?", vbYesNo + vbQuestion)
If answer = vbYes Then
If Sheet_Exists("Logged Changes") = False Then
Sheet_Name = "Logged Changes"
Worksheets.Add(After:=Sheets(Sheets.Count)).Name = Sheet_Name
End If
Worksheets("Logged Changes").Range("A1") = "Edited Requirements"
Else
Unload Me
End If
End Sub
I have tried fiddling around with the code, but didn't want to clog it up with any unnecessary/broken lines. Any help would be greatly appreciated!
Try this:
Option Explicit
Private Sub CompareBasic()
Const SHT_REPORT As String = "Logged Changes"
Dim actSheet As Range
Dim c As Integer
Dim o As Long
Dim p As Long
Dim r As Long
Dim change As Long, wsOrig As Worksheet, wsNew As Worksheet, wsReport As Worksheet
Dim dataOrig, dataNew, rngData As Range, v1, v2, bDiff As Boolean
Dim arrUpdates
Set wsOrig = Worksheets("Original")
Set wsNew = Worksheets("Version 2")
o = wsOrig.Cells(2, Columns.Count).End(xlToLeft).Column
p = wsOrig.Range("A" & Rows.Count).End(xlUp).Row
Set rngData = wsOrig.Range("A2", wsOrig.Cells(p, o))
dataOrig = rngData.Value 'get an array of data
dataNew = wsNew.Range(rngData.Address).Value 'array of new data
ReDim arrUpdates(1 To rngData.Cells.Count, 1 To 3) 'for change info
change = 0
For r = 1 To UBound(dataOrig, 1)
For c = 1 To UBound(dataOrig, 2)
v1 = dataOrig(r, c)
v2 = dataNew(r, c)
If Len(v1) > 0 Or Len(v2) > 0 Then
If IsNumeric(v1) Then
bDiff = v1 <> v2
Else
bDiff = StrComp(v1, v2, vbBinaryCompare) <> 0
End If
End If
'any difference?
If bDiff Then
change = change + 1
With rngData.Cells(r, c)
arrUpdates(change, 1) = .Address
.Interior.ColorIndex = 37
End With
arrUpdates(change, 2) = v1
arrUpdates(change, 3) = v2
End If
Next c
Next r
If MsgBox("Do you want to run the Report?", vbYesNo + vbQuestion) = vbYes Then
With GetSheet(SHT_REPORT, ThisWorkbook)
.UsedRange.ClearContents
.Range("A1") = "Edited Requirements"
.Range("A3").Resize(1, 3).Value = Array("Address", wsOrig.Name, wsNew.Name)
.Range("A4").Resize(change, 3).Value = arrUpdates
End With
Else
'Unload Me
End If
End Sub
'return as sheet from wb by name (and create it if it doesn't exist)
Function GetSheet(wsName, wb As Workbook) As Worksheet
Dim rv As Worksheet
On Error Resume Next
Set rv = wb.Worksheets(wsName)
On Error GoTo 0
If rv Is Nothing Then
Set rv = wb.Worksheets.Add(After:=wb.Worksheets(wb.Worksheets.Count))
rv.Name = "Logged Changes"
End If
Set GetSheet = rv
End Function
Sheet Differences
Option Explicit
Sub logChanges()
Const ws1Name As String = "Original"
Const ws2Name As String = "Version 2"
Const wsResult As String = "Logged Changes"
Const FirstRow As Long = 2
Const FirstColumn As Long = 1
Const LastRowColumn As Long = 1
Const LastColumnRow As Long = 2
Const ResultFirstCell As String = "A2"
Dim Headers As Variant
Headers = Array("Id", "Address", "Original", "Version 2")
Dim wb As Workbook: Set wb = ThisWorkbook
Dim ws As Worksheet: Set ws = wb.Worksheets(ws1Name)
Dim LastRow As Long
LastRow = ws.Cells(ws.Rows.Count, LastRowColumn).End(xlUp).Row
Dim LastColumn As Long
LastColumn = ws.Cells(LastColumnRow, ws.Columns.Count) _
.End(xlToLeft).Column
Dim rng As Range
Set rng = ws.Range(ws.Cells(FirstRow, FirstColumn), _
ws.Cells(LastRow, LastColumn))
Dim Data1 As Variant: Data1 = rng.Value
Set ws = wb.Worksheets(ws2Name)
Dim Data2 As Variant: Data2 = ws.Range(rng.Address).Value
Dim Result() As Variant
Dim i As Long, j As Long, k As Long
For i = 1 To UBound(Data1)
For j = 1 To UBound(Data1, 2)
If Data1(i, j) <> Data2(i, j) Then GoSub writeResult
Next j
Next i
If k > 0 Then
transpose2D Result
On Error GoTo MissingResultSheet
Set ws = wb.Worksheets(wsResult)
On Error GoTo 0
ws.Range(ws.Range(ResultFirstCell), _
ws.Cells(ws.Rows.Count, ws.Columns.Count)).Clear
ws.Range(ResultFirstCell).Resize(k, UBound(Result, 2)).Value = Result
MsgBox "Found '" & k & "' difference(s) in range '" _
& rng.Address(False, False) & "'.", vbInformation
Else
MsgBox "Found no differences in range '" _
& rng.Address(False, False) & "'.", vbExclamation
End If
Exit Sub
writeResult:
k = k + 1
ReDim Preserve Result(1 To 4, 1 To k)
Result(1, k) = k
Result(2, k) = getAddress(i + FirstRow - 1, j + FirstColumn - 1)
Result(3, k) = Data1(i, j)
Result(4, k) = Data2(i, j)
Return
MissingResultSheet:
If Err.Number = 9 Then
wb.Worksheets.Add After:=wb.Sheets(wb.Sheets.Count)
With ActiveSheet
.Name = wsResult
If .Range(ResultFirstCell).Row > 1 Then
.Range(ResultFirstCell).Offset(-1) _
.Resize(, UBound(Headers) + 1).Value = Headers
End If
End With
Resume ' i.e. the code continues with Set ws = wb.Worksheets(wsResult)
Else
'?
Exit Sub
End If
End Sub
Function getAddress(aRow As Long, aColumn As Long) As String
getAddress = ActiveSheet.Cells(aRow, aColumn).Address(False, False)
End Function
Sub transpose2D(ByRef Data As Variant)
Dim i As Long, j As Long
Dim Result As Variant
ReDim Result(LBound(Data, 2) To UBound(Data, 2), _
LBound(Data) To UBound(Data))
For i = LBound(Data) To UBound(Data)
For j = LBound(Data, 2) To UBound(Data, 2)
Result(j, i) = Data(i, j)
Next j
Next i
Data = Result
End Sub
This solution for converting a column number to a string without using objects Function to convert column number to letter? could be used to write a descent getAddress function.

Is VBA able to store each array individually and wait to print them to a template?

Is there a way to have this script form the entire array based off the rows I want it to extract based on the IF Statement?
I know this finds a name on the Mgrs worksheet, and finds those rows in the Data worksheet, but then it directly prints it after forming the array. Can I have this code store all of the data, and then wait to print the data on a template that I format myself?
Option Explicit
Sub CIB_Cuts()
Dim j As Long, k As Long, x As Long
Dim varArray() As Variant
Dim varArray2() As Variant
ReDim varArray(1 To 19, 1 To 1)
Dim strManager As String, strEC As String, strLogin As String
Dim BASEPATH As String, strNewPath As String, strFileName As String
Dim Wb As Workbook
Dim mgrRow As Long
Dim colManager As Long
colManager = 3
Dim colLogin As Long
colLogin = 4
Dim colEC As Long
colEC = 5
BASEPATH = "M:\Final Files\"
Call speedupcode(True)
For mgrRow = 2 To ThisWorkbook.Worksheets("Mgrs").UsedRange.Rows.Count
If ThisWorkbook.Worksheets("Mgrs").Cells(mgrRow, 3) <> "" Then
strManager = ThisWorkbook.Worksheets("Mgrs").Cells(mgrRow, 3)
With ThisWorkbook.Worksheets("Data")
ReDim varArray(1 To UBound(varArray, 1), 1 To 1)
x = 1
For k = 1 To UBound(varArray, 1)
varArray(k, x) = .Cells(1, k)
Next
For j = 2 To .UsedRange.Rows.Count + 1
If strManager = .Cells(j, colManager) Then
x = x + 1
ReDim Preserve varArray(1 To UBound(varArray, 1), 1 To x)
For k = 1 To UBound(varArray, 1)
If k = 1 Then
varArray(1, x) = CStr(Format(.Cells(j, k), "000000000"))
Else
varArray(k, x) = .Cells(j, k)
End If
strEC = .Cells(j, colEC)
strManager = .Cells(j, colManager)
strLogin = .Cells(j, colLogin)
Next
End If
Next
End With
strFileName = strLogin & " - " & strManager & " - " & "Shift Differential Validation" & ".xlsx"
ReDim varArray2(1 To UBound(varArray, 2), 1 To UBound(varArray, 1))
Set Wb = Workbooks.Add(XlWBATemplate.xlWBATWorksheet)
With Wb
With .Worksheets("Sheet1")
.Columns(1).NumberFormat = "#"
.Columns(15).NumberFormat = "0%"
For j = 1 To UBound(varArray, 2)
For k = 1 To UBound(varArray, 1)
varArray2(j, k) = varArray(k, j)
Next
Next
.Range(.Cells(1, 1), .Cells(UBound(varArray, 2), UBound(varArray, 1))) = varArray2
Call DataValidation
Call Header
.Range("C2").Select
ActiveWindow.FreezePanes = True
.Cells.EntireColumn.AutoFit
.Rows("1:1").Font.Bold = True
Call protect
End With
.SaveAs strNewPath & strFileName, Password:="password", FileFormat:=51
.Saved = True
.Close
End With
Set Wb = Nothing
End If
Next
Call speedupcode(False)
End Sub
You could store the array each time in an overarching array or a collection and loop that at the end...
Public Sub test()
Dim varArray2() As Variant, results As Collection
'other code..
Set results = New Collection
results.Add varArray2
End Sub
You could also use Select Case , or something distinctive during the loop, to determine a key and populate a dictionary with the arrays as values which might make retrieval of specific items easier.

is it possbile to create an collection of arrays in vba?

first of all, i'd like to say, i've sarched thorugh the net, but i haven't run into such a thing. i've seen collection of collections, or array of arrays, but not a collection of array.
what i want to do is, to collect ID's in collections for each District. Finally, i will join the values in the collections with Join function and ";" as delimiter, and then print them in a range of 4 column as a lookup list, for each class. For example;
Class2(0) will include 54020 and 30734, class2(1) will include 58618, class1(4) will include none, class3(7) will include 35516,34781 and 56874, and so on.
i want to loop through column C and put a select case statment to check the class and then assign the values to collections
Sub dict_coll()
Dim class1() As New Collection
Dim class2() As New Collection
Dim class3() As New Collection
Dim class4() As New Collection
Dim dict As New Scripting.Dictionary
Set dRange = range(range("a2"), range("a2").End(xlDown))
i = 0
For Each d In dRange
If Not dict.Exists(d.Value) Then
dict.Add key:=d.Value, item:=i
i = i + 1
End If
Next d
Set cRange = range(range("c2"), range("c2").End(xlDown))
For Each c In cRange
Select Case c.Value
Case "class1"
class1(dict(c.offset(0,-2).value)).Add c.Offset(0, 1).Value 'fails here
Case "class2"
class2(dict(c.offset(0,-2).value)).Add c.Offset(0, 1).Value 'fails here
Case "class3"
class3(dict(c.offset(0,-2).value)).Add c.Offset(0, 1).Value 'fails here
Case Else
class4(dict(c.offset(0,-2).value)).Add c.Offset(0, 1).Value 'fails here
End Select
Next c
End Sub
and what i want to see is as foloowing:
is there any easier and proper way of what i wanna do? any help wil be appreciated.
thanks
I didnt see that sb variable defined in your code.
Anyway, for me I see a case of straightforward arrays: There is fixed dimension of classes so it good enough for me. Furthermore, you can print back to worksheet so easily.
Public Sub test()
Const strPrefix = "class"
Dim districtRange As Range, outputRange As Range, r As Range
Dim arr() As String
Dim i As Long, j As Long, x As Long, y As Long
Dim district As String, str As String, idVal As String
Dim arr2 As Variant
Application.ScreenUpdating = False
ReDim arr(1 To 5, 1 To 1)
arr(1, 1) = "District"
arr(2, 1) = "Class 1"
arr(3, 1) = "Class 2"
arr(4, 1) = "Class 3"
arr(5, 1) = "Class 4"
Set districtRange = Range(Range("A2"), Range("C2").End(xlDown))
arr2 = districtRange.Value
For x = LBound(arr2, 1) To UBound(arr2, 1)
district = arr2(x, 1)
i = Val(Mid(arr2(x, 3), Len(strPrefix) + 1))
idVal = arr2(x, 2)
j = inArray(arr, district, 1) 'returns -1 if not found
If j >= 0 Then
arr(i + 1, j) = IIf(arr(i + 1, j) = "", idVal, arr(i + 1, j) & ";" & idVal)
Else
ReDim Preserve arr(1 To 5, 1 To UBound(arr, 2) + 1)
arr(1, UBound(arr, 2)) = district
arr(i + 1, UBound(arr, 2)) = idVal
End If
Next x
Set outputRange = Range("E1")
outputRange.Resize(UBound(arr, 2), UBound(arr, 1)).Value = Application.Transpose(arr)
outputRange.Sort Key1:=Range("E1"), Header:=xlYes, Order1:=xlAscending
Application.ScreenUpdating = True
End Sub
Public Function inArray(arr As Variant, k As String, Optional rowNum As Long, Optional colNum As Long) As Long
Dim i As Long, j As Long
inArray = -1
If rowNum Then
For i = LBound(arr, 2) To UBound(arr, 2)
If arr(rowNum, i) = k Then
inArray = i
Exit Function
End If
Next i
Else
For i = LBound(arr, 1) To UBound(arr, 1)
If arr(i, colNum) = k Then
inArray = i
Exit Function
End If
Next i
End If
End Function
by the way, i've found another solution, usinf both dictionary and 3-dimension array.
Sub test()
Dim Blg As New Scripting.Dictionary
Dim Sgm As New Scripting.Dictionary
Dim Siciller() As String
ReDim Siciller(0 To 23, 0 To 3, 0 To 5)
Set alanBolge = range(range("a2"), range("a2").End(xlDown))
Set alanSegment = range(range("c2"), range("c2").End(xlDown))
i = 0
For Each d In alanBolge
If Not Blg.Exists(d.Value) Then
Blg.Add Key:=d.Value, item:=i
i = i + 1
End If
Next d
k = 0
For Each d In alanSegment
If Not Sgm.Exists(d.Value) Then
Sgm.Add Key:=d.Value, item:=k
k = k + 1
End If
Next d
'data reading
For Each d In alanBolge
Siciller(Blg(d.Value), Sgm(d.Offset(0, 2).Value), dolusay(Siciller, Blg(d.Value), Sgm(d.Offset(0, 2).Value)) + 1) = d.Offset(0, 1).Value
Next d
'output
For x = 1 To 4
For y = 1 To 24
Set h = Cells(1 + y, 5 + x)
h.Select
h.Value = sonucgetir(Siciller, Blg(h.Offset(0, -x).Value), Sgm(h.Offset(-y, 0).Value))
Next y
Next x
End Sub
Public Function dolusay(ByVal data As Variant, ByVal i1 As Integer, ByVal i2 As Integer) As Integer
Dim count As Integer
count = 0
For j = 0 To UBound(data, 3) - 1
If Len(data(i1, i2, j)) > 0 Then
count = count + 1
End If
Next
dolusay = count
End Function
Public Function sonucgetir(ByVal data As Variant, ByVal i1 As Integer, ByVal i2 As Integer) As String
sonucgetir = ""
For i = 0 To UBound(data, 3)
If Len(data(i1, i2, i)) > 0 Then
x = data(i1, i2, i) & ";" & x
sonucgetir = Left(x, Len(x) - 1)
End If
Next i
End Function

Adding to a string array alphabetically

I'm looking for a way to add a string (from a cell) to a string array alphabetically.
For instance:
string array = {"apple", "banana", "orange"}
add "cherry":
string array = {"apple", "banana", "cherry", "orange"}
Hence if I do sheets(1).range("A1").value = new string array, the entire array will be in one cell.
I found a function online that sorts selected cells alphabetically, but not sure if it helps in my instance.
Function Alphabetize(vStrings As Variant, separator As String) As String
Dim v As Variant, vSorted As Variant
Dim i As Long, j As Long, n As Long
Dim bDone As Boolean
For Each v In vStrings
n = n + 1
Next
ReDim vSorted(1 To n)
ReDim pos(1 To n)
For Each v In vStrings
i = i + 1
vSorted(i) = v
Next
For j = 2 To n
bDone = True
For i = 2 To n
If vSorted(i) < vSorted(i - 1) Then
v = vSorted(i - 1)
vSorted(i - 1) = vSorted(i)
vSorted(i) = v
bDone = False
End If
Next
If bDone Then Exit For
Next
For i = 1 To n
If vSorted(i) <> "" Then
If i = 1 Then
Alphabetize = separator & vSorted(i)
Else
If vSorted(i) <> vSorted(i - 1) Then Alphabetize = Alphabetize & separator & vSorted(i)
End If
End If
Next
Alphabetize = Mid$(Alphabetize, 2)
End Function
You can use the System.Collections.SortedList class from the .NET library, if you want. Then there's no need to worry about sorting.
Dim objList As Object
Set objList = CreateObject("System.Collections.SortedList")
objList.Add "apple", ""
objList.Add "banana", ""
objList.Add "orange", ""
objList.Add "cherry", ""
Dim i As Long
For i = 0 To objList.Count - 1
Debug.Print objList.GetKey(i)
Next
Prints:
apple
banana
cherry
orange
If you want to combine the values into a string, just concatenate them as you loop through the values or you can transfer to an array and use Join to create the string:
ReDim a(objList.Count - 1) As String
Dim i As Long
For i = 0 To objList.Count - 1
a(i) = objList.GetKey(i)
Next
' Combine strings into the format: {"string1", "string2", "stringN"}
Sheet1.Range("A1").Value = "{""" & Join(a, """, """) & """}"
It isn't clear where the declaration or assignment of vStrings and 'cherry' are but here is a sub calling the function that appends the array and returns a delimited list (single text value) to Sheet1's A1.
Sub main()
Dim string_array As Variant, new_string As String
string_array = Array("apple", "banana", "orange")
new_string = "cherry"
Sheets(1).Range("A1").Value = add_and_alphabetize(string_array, new_string, sDELIM:=Chr(44))
End Sub
Function add_and_alphabetize(vSTR As Variant, sSTR As String, _
Optional sDELIM As String = ";", Optional bDESC As Boolean = False)
Dim i As Long, j As Long, vTMP As Variant
If CBool(Len(sSTR)) Then
ReDim Preserve vSTR(LBound(vSTR) To UBound(vSTR) + 1)
vSTR(UBound(vSTR)) = sSTR
End If
For i = LBound(vSTR) To UBound(vSTR) - 1
For j = i To UBound(vSTR)
If (vSTR(i) < vSTR(j) And bDESC) Or (vSTR(i) > vSTR(j) And Not bDESC) Then
vTMP = vSTR(j)
vSTR(j) = vSTR(i)
vSTR(i) = vTMP
End If
Next j
Next i
add_and_alphabetize = Join(vSTR, sDELIM)
End Function
I've added options to specify the delimiter character (defaulted as a semi-colon) and change the order of the sort.

Resources