vba: get unique values from array: Explanation [closed] - excel

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 3 years ago.
Improve this question
I am having difficulties in trying to understand the following code. I found it here in the following link: vba: get unique values from array
Dim d As Object
Set d = CreateObject("Scripting.Dictionary")
'Set d = New Scripting.Dictionary
Dim i As Long
For i = LBound(myArray) To UBound(myArray)
d(myArray(i)) = 1
Next i
Dim v As Variant
For Each v In d.Keys()
'd.Keys() is a Variant array of the unique values in myArray.
'v will iterate through each of them.
Next v
EDIT: I quite understand the whole code but I could not understand the last section being
Dim v As Variant
For Each v In d.Keys()
'd.Keys() is a Variant array of the unique values in myArray.
'v will iterate through each of them.
Next v
and I cannot understand this line
d(myArray(i)) = 1
EDIT: I am looking for a code that executes the same objective but I would rather want to understand fully what I am applying than just copy and paste something that I do not understand.
More specifically, there are several elements in the macro that I am constructing and this one is among the ones I am looking for.
As first objective I need to find the duplicates in my dataset
After finding the duplicates I need to count how duplicates there are if there are 4 duplicates row my item is complete,
Then, if there are more than 4 duplicates, I need to transfer the duplicates to another sheet and store them there
On the other hand, if there are less than 4 duplicates, I would need to find such items and try to match these items with an inventory to try to find out the remaining elements in order to stack a full set of 4 elements.
This macro will serve me to fulfill point 4. Once I identify the items that have less than 4, I need to find such items and try to match them with the ones that I have in another sheet. I need to do so with the code above as I would rather use an array in a macro than functions in excel itself in order to avoid confusion to the user with phantom figures.

Section by Section:
Dim d As Object
Set d = CreateObject("Scripting.Dictionary")
'Set d = New Scripting.Dictionary
This creates the dictionary object
Dim i As Long
For i = LBound(myArray) To UBound(myArray)
d(myArray(i)) = 1
Next i
With dictionary objects, there are two ways to add a new item:
d.Add Key, Value
This method causes an error if the dictionary already has that key
d(Key) = Value
This method is technically a reassignment for the value of the specified key. If the key doesn't exist, it gets added implicitly. If the key already exists, the value just gets updated.
So what the code is doing, is it cycles through each value in the array and:
Reassigns the current index as the dictionary value with the current dictionary key (the array's value)
If the key doesn't already exist, create it.
This results in a dictionary with one key for every unique value. Any duplicate values would have just been reassigned the value for the existing key, instead of creating a new key.
Dim v As Variant
For Each v In d.Keys()
'd.Keys() is a Variant array of the unique values in myArray.
'v will iterate through each of them.
Next v
Elaboration: d.Keys returns all of the keys in the dictionary in the form of an array. Since the keys are the unique values from myArray, d.Keys is an array on the unique values from myArray.

Related

Trying to store user values into an array

I am trying to create an array of a user set length that users can add values to that will be saved and output on multiple sheets. I am very new to VBA so I do not know if what I am trying to do is possible but I have tried a few methods unsuccessfully.
This is the code I have so far
Sub addCost()
Dim costArray() As Variant
ReDim Preserve costArray(1 To Range("b2").Value)
For i = 1 To Range("b2").Value
costArray(i) = 0
Next i
Dim newCost As Variant
Dim costYear As Variant
newCost = InputBox("New cost amount:")
costYear = InputBox("Year new cost is active:")
costArray(costYear) = newCost
End Sub
Here is what the input tab looks like in excel
With the length of the array being the project lifespan and the add new cost activating the code, clear costs are still in progress. Is there a way for the array to store after multiple executions of the addCost sub?
Thanks!
This link Microsoft shows some methods of store values after the macro ending (in your case, sub addCost)
I think the first solution will be good for you.
Other solutions is use Access to store data (specially if you need these data over time) or a new and clean worksheet where you can store array entries in a cell (This is a very practical solution if the number of entries does not get too big)

Printing Array in one row in nested xml using VBA

I am using xml in VBA which is taking data from an API. I have a nested XMl I am calling but one creates a new array. I can see how to add each nested xml to a cell in excel where they have one value but how would I send the array to cells so that each time an event happened it was added to the next column in the same row?
Debug.Print result("month")("day")("events")("elapsed")
elapsed is an array which holds a time for each event and there are multiple events per day maybe up to 10
WrkSht.Cells(Count, 1).Value = result("elapsed")
would print the first event but I would like the second event to appear in say next column and I cannot find how to code that etc
I am sure this is probably simple but I have searched and cannot see an explanation of how to handle this.
Thanks
This may work:
Dim a as Variant, b as Long
Set a = result("elapsed")
For b = 0 to UBound(a)
WrkSht.Cells(cnt, 1).Offset(,b).Value = a(b)
Next
If not, this most likely will:
Dim a as Object, b as Object, c as Long
Set a = result("elapsed")
For each b in a
WrkSht.Cells(cnt, 1).Offset(,c).Value = b
c = c + 1
Next
Also note that I changed the Count variable name to avoid confusion with the native Count method.

VBA/Excel - Matching Column values with pre-defined sets

I have a case where I have a pre-defined set of values/codes what in a combination make some message. I also have an incoming file that I have to analyze on the codes, compare the sets against predefined values. The problem is that the incoming file doesn't exactly match my library:
In my library I have set of 4 columns and each row has it's unique meaning. I want to get that meaning as a string to further proceed with calculations. The problem is that the incoming file is not consistent. It doesn't follow exact sequence as in pre-defined file.
I need to compare them regardless of sequence. After being matched I want to grab corresponding Meaning from Library and proceed working with Case in my file.
Any ideas how to implement it in VBA?
Offhand, you could create a VBA function that would return a string representing the unique values.
If there is some character that will never be in the values, you could delimit the values with that character (such as _):
Function GetUniqueValuesString(rng As Range) As String
Dim rngValues() As Variant
rngValues = rng.Value
' The following line requires a reference to Microsoft Scripting Runtime
' (via Tools -> References...)
Dim dict As New Scripting.Dictionary
'The function only parses the first row of the range
Dim i As Integer
For i = 1 To UBound(rngValues, 2)
dict(rngValues(1, i)) = 1 ' 1 here is a dummy value
Next
GetUniqueValuesString = Join(dict.Keys, "_")
End Function
(If every value is always the same number of characters, you could simply join them, without any delimiter.)
Using this function against a horizontal cell range:
=GetUniqeValuesString(A4:D4)
should return a string with only the unique values:
BGAA_TGHJ_WETY
If you apply this function to both the library rows and the file rows, you should be able to match on the function's returned value.
Note that the function has a few limitations that might need to be resolved:
It assumes the order of the values will be the same. In other words, BGAA, TGHJ, WETY will resolve to a different string than BGAA, WETY, TGHJ.
The function only joins the first row; other rows are ignored.

Excel find remaining columns efficiently

I have a script (thanks to SO for the help with that one!) to allow a user to select a number of discontinuous columns and insert their indexes into an array. What I need to be able to do now is efficiently select the remaining columns i.e. the ones that the user didn't select into another array to perform a separate action on these columns.
For example, the user selects columns A,C,F,G and these indexes are put into the array Usr_col(). The remaining columns (B,D,E) need to be stored in the array rem_col()
All I can think of right now is to test every used column's index against the array of user-selected columns and, if it is not contained in that array, insert it into a new array. Something like this:
For i = 1 to ws.cells(1, columns.count).end(xltoright).column
if isinarray(i, Usr_col()) = false Then
rem_col(n) = i
n = n+1
end if
next
I am just looking for a more efficient solution to this.
I agree with #ScottHoltzman that this site wouldn't normally be the arena to make working code more efficient. However, this question puts a different slant on your previous one, as the most obvious solution would be to assign column numbers to one or other of your arrays in one loop.
The code below gives you a skeleton example. You'd need to check the user's selection for proper columns. Also, it isn't great form to redimension an array within the loop, but if the user selects adjacent columns then you'd need to acquire area count and column count to get the array size. I'll leave that to you if rediming within the loop jars with you:
Dim targetCols As Range, allCols As Range
Dim selColNum() As Long, unselColNum() As Long
Dim selIndex As Long, unselIndex As Long
Set targetCols = Application.InputBox("Select your columns", Type:=8)
For Each allCols In Sheet1.UsedRange.Columns
If Intersect(allCols, targetCols) Is Nothing Then
ReDim Preserve unselColNum(unselIndex)
unselColNum(unselIndex) = allCols.Column
unselIndex = unselIndex + 1
Else
ReDim Preserve selColNum(selIndex)
selColNum(selIndex) = allCols.Column
selIndex = selIndex + 1
End If
Next

Remove duplicates in a collection and put into array

I have a collection of Applicants. The collection has Names, University, Age, Date, etc.
I would like to create an array that just holds the unique Names from the Applicants collection.
I wanted to somehow create a new dictionary that uses the Names as keys since keys can't be duplicates:
Dim z As Variant
Dim d As Object
Set d = CreateObject("Scripting.Dictionary")
For Each z In Applicants
d(z("Names")) = 1
Next
However I do not know if this would work because I am running into errors. I want to create an array afterwards that will hold the unique keys or the Names in this case.
You need to test if the key exists before adding or you will throw an error. Additionally, you have the non-unique .Item in a Scripting.Dictionary that can store single or delimited fields from the same record.
For Each z In Applicants
if not d.exists(z("Names")) then
d.Add Key:=z("Names"), Item:=z("University") & "|" & z("Age") & "|" & z("Date")
end if
Next
I'm not sure about z("Names") but you have not provided enough information about Applicants to prove more than what your sample was using. The .Item. can be retrieved using the key and a Split function on the delimiter will create an array.

Resources