remove duplicate rows in array - arrays

I have a question about arrays. First let me show you the code that I have got:
Dim TopStud() As Variant
TopStud = Range("A1", Range("A2").End(xlDown).End(xlToRight))
'code that removes duplicate values in array
'end code
Worksheets.Add
Range(ActiveCell, ActiveCell.Offset(UBound(TopStud, 1) - 1, UBound(TopStud, 2) - 1)).Value = TopStud
The code above shows how I get a range of values in an array. I want to remove duplicate values that is been saved in this array into a new worksheet. See above. Is there a easy way to do this?
I want the following result:

If you want to remove the whole record for any duplicates in the current column:
Cells.RemoveDuplicates Columns:=ActiveCell.Column,Header:=xlYes

Related

Finding the average of each column in a multi array in excel vba

I have an array that is
myarray (1 to 37, 1 to 44) as variant
I'm trying to speed up my spreadsheet so rather than using big tables with lots of formulas in I'm turning to arrays, calculating them in memory and then writing the array to the sheet like such.
'Write array to worksheet.
Sheet1.Range("A1").Resize(UBound(myarray, 1), UBound(myarray, 2)).Value = myarray
This is working well except I'm not sure how to write code to perform certain calculations on specific rows or columns of the array. So if I wanted to know the average of all the elements in row 2 for example, how would that be written?
Many thanks in advance.
P.S. I should say I know I can cycle through and perform the average like so but I am more talking about using the various worksheet functions on specific rows or columns, this is what I don't understand how to write.
Thanks but I've sussed it now. I place all the elements of that particular row or column into a new array then simply use the worksheet function command. So in this example I am using functions on each column of the myarray. I'll post this in case it helps anyone else with worksheet functions in arrays.
For i = 1 To 44
Erase Calc1Array()
ReDim Calc1Array(1 To 37)
For j = 1 To 37
Calc1Array(j) = MyArray(j, i)
Next j
Answer1 = Application.WorksheetFunction.Max(Calc1Array)
Answer2 = Application.WorksheetFunction.Average(Calc1Array)
Answer3 = Application.WorksheetFunction.StDev(Calc1Array)
Next i

How to insert values from a one dimensional array given by ETABS into a range in excel using VBA

I am trying to insert values from a one dimensional array given to me by a program (ETABS) into a range in Excel using VBA.
This is how the results are returned to you by the ETABS program (please read to understand): http://docs.csiamerica.com/help-files/common-api(from-sap-and-csibridge)/SAP2000_API_Fuctions/Analysis_Results/Results/Analysis_Results_Remarks.htm
Therefore in order for me to insert ONE result into cell "A1" in Excel I just use this code (WHICH WORKS):
Range("A1").Value = U1(0)
But if I want to insert ALL of the results into a certain Range I am running into all types of problems..I've tried many codes, but this one seemed to be the most reasonable:
Range("A1:A" & (NumberResults - 1)).Value = (U1(0) - U1(NumberResults - 1))
I usually get only the first value repeated all throughout the range instead of the whole set of values.
Does anybody have an idea of how to make all of the values of the array appear in the designated range?
Thanks!
Because the arrayU1() is zero-based:
Dim i As Long
For i = LBound(U1) To UBound(U1)
Range("A" & i + 1).Value = U1(i)
Next i

Creating a Macro to Index Data from Government Website

I provide the link here: http://quickstats.nass.usda.gov/results/320F1D82-1064-30F1-809E-F77E509EC508. I would like to learn how to perform this task using a macro/script in Excel VBA. The problems which I have been unable to overcome myself are:
1) Not all the weeks in the year are represented in the data. I am not sure how to sort the data by particular week, not sure what command I would need.
2) Is is possible to the Excel function VLOOKUP in my vba script in order to select all the distinct values, say Week14 or Week15, before performing the calculation for each week? If so, how is it incorporated? My idea was to just perform a VLOOKUP in the macro to search for the five different crop conditions.
My first question on this topic was about how to download the information off the website, see Building a Macro to Download Data off a Website into Excel. I suggest that this is the first button, "download", and then there should be a second button to sort the data called "sort".
CommandButton_1 is for download data, see linked question.
Private Sub CommandButton1_Click()
Dim thisWb, downloadWb As Workbook
Set thisWb = ActiveWorkbook
Set downloadWb = Workbooks.Open("http://quickstats.nass.usda.gov/data/spreadsheet/4C43034A-0EAA-3171-B4FC-84CC95FC6E0C.csv")
downloadWb.Worksheets(1).Range("A1:U2613").Copy Destination:=thisWb.Worksheets(3).Range("A8")
downloadWb.Close
End Sub
This works very well. Now the second button (Sort Data) it was suggested below that
Private Sub CommandButton2_Click()
Public Function WeekTotal(Condition As String, Table As Range) As Integer
Dim rRow As Range
Dim xVal As Integer
xVal = 0
For Each rRow In Table.Rows
If InStr(LCase(rRow.Cells(1, 10).Value), "very") > 0 And LCase(Condition) = "poor" Then
'skip if row includes 'very', but the condition is 'poor' and not 'very poor'
ElseIf InStr(LCase(rRow.Cells(1, 10).Value), LCase(Condition)) > 0 Then
xVal = xVal + rRow.Cells(1, 13).Value
End If
Next rRow
WeekTotal = xVal
End Function
End Sub
This does not seem to work. Here is a picture, slightly altered width of columns, of what I am trying to deal with.
In my opinion, a macro is over-complicating a simple problem.
Simply add a new column with a VLOOKUP on the value that corresponds to your rating. To accomplish this, you will need a reference range that can provide such a value. (See screenshot 1).
In a new worksheet, list your weeks, and use SUMIF to calculate the total of the values in your vlookup column for each corresponding week. (See screenshot 2).
If you need to do a more sophisticated calculation, then provide additional detail and I'll modify this answer to help.
I45 = "Excellent"
J2:J36 is the Data Item column
M2:M36 is the Value column
=SUM(IF(ISERROR(SEARCH(I45,$J$2:$J$36)),0,$M$2:$M$36))
Returns: 14
This is an array formula, so you have to press Ctrl+Shift+Enter, not just Enter. (You will know you did it correctly because it will look like this in the formula bar: {=SUM(IF(ISERROR(SEARCH(I45,$J$2:$J$36)),0,$M$2:$M$36))}
It automatically adds { and } when you press Ctrl+Shift+Enter - you do not type them in.
What this formula does:
Search("Excellent", $J$2) would look for the string "Excellent" in J2 and return the position it found the string or an error if it did not find the string. We don't care about the actual value - we just want to know if it throws an error or not. We turn this into an array by using $J$2:$J$36. You can't see it, but what this actually does is return an array of values that might look like this :
{44;#VALUE!;#VALUE!;#VALUE!;#VALUE!;44;#VALUE!;#VALUE!;#VALUE!;#VALUE!;44;#VALUE!;#VALUE!;#VALUE!;#VALUE!;44;#VALUE!;#VALUE!;#VALUE!;#VALUE!;44;#VALUE!;#VALUE!;#VALUE!;#VALUE!;44;#VALUE!;#VALUE!;#VALUE!;#VALUE!;44;#VALUE!;#VALUE!;#VALUE!;#VALUE!}
By using ISERROR(SEARCH("Excellent", $J$2:$J$36)) we change that internal array into this:
{FALSE;TRUE;TRUE;TRUE;TRUE;FALSE;TRUE;TRUE;TRUE;TRUE;FALSE;TRUE;TRUE;TRUE;TRUE;FALSE;TRUE;TRUE;TRUE;TRUE;FALSE;TRUE;TRUE;TRUE;TRUE;FALSE;TRUE;TRUE;TRUE;TRUE;FALSE;TRUE;TRUE;TRUE;TRUE}
If it fails to find "Excellent", ISERROR will be TRUE, so we want to find the value for all the FALSE values in this array. We do this using IF. If the SEARCH is an error, 0, else give us the value another array - $M$2:$M$36 (the value column).
=IF(ISERROR(SEARCH("Excellent", $J$2:$J$36)), 0,$M$2:$M$36)
This gives us the following:
{2;0;0;0;0;2;0;0;0;0;2;0;0;0;0;2;0;0;0;0;2;0;0;0;0;2;0;0;0;0;2;0;0;0;0}
Since your sample data had 2 for excellent for each week.
Finally we add SUM() around it all to sum up the values.
=SUM(IF(ISERROR(SEARCH("Excellent", $J$2:$J$36)), 0,$M$2:$M$36))
Again, since this is an array formula, if you just hit enter with this formula, it will return 0, but if you hit Ctrl+Shift+Enter it will give you the correct result of 14.
If you want to use VBA, simply as practice, here is how you could use a custom formula.
To use this function you would type the following into a cell:
=WeekTotal("Excellent",$A$2:$M$36)
VBA code:
Public Function WeekTotal(Condition As String, Table As Range) As Integer
Dim rRow As Range
Dim xVal As Integer
xVal = 0
For Each rRow In Table.Rows
If InStr(LCase(rRow.Cells(1, 10).Value), "very") > 0 And LCase(Condition) = "poor" Then
'skip if row includes 'very', but the condition is 'poor' and not 'very poor'
ElseIf InStr(LCase(rRow.Cells(1, 10).Value), LCase(Condition)) > 0 Then
xVal = xVal + rRow.Cells(1, 13).Value
End If
Next rRow
WeekTotal = xVal
End Function

VBA AutoFilter multiple worksheets based on array of numbers, ignore if not in list

Let's say I have a workbook with 3 worksheets on it. I've filtered down the first sheet based on column State that equals Ohio. I then get a list of values from that filtered list from column ID and put them into an Integer/Long array. Basically I put all the ID's for each row that has the state column Ohio.
I am now trying to filter the remaining tables based on their ID column where they match my array of ID's. The problem is when it comes across filtered ID's that are not in the new sheet, instead of providing me with the matches for each sheet, I am left with only the last matching value. Here's an example of my VBA trying to filter the remaining sheets:
For Each sheet In Worksheets
If sheet.Name <> "Sheet1" Then
sheet.Activate
columnNum = ActiveSheet.UsedRange.Find("ID").Column
ActiveSheet.AutoFilterMode = False
ActiveSheet.UsedRange.AutoFilter
'***Problem is here
ActiveSheet.UsedRange.AutoFilter Field:=columnNum, Criteria1:=mainIDs, Operator:=xlFilterValues
End If
Next
As I mentioned earlier mainIDs is an array of Integer that is being carried over to each sheet to filter on. Why is it only bringing me back the last match? Do I need to somehow tell it to ignore filtered values that aren't in the new sheet? How?
EDIT: Here's how I filled my array
Dim mainIDs() As Long, size As Integer, i As Integer
size = ActiveSheet.UsedRange.Columns(1).SpecialCells(xlCellTypeVisible).Cells.Count - 2
ReDim mainIDs(size)
i = 0
For Each row In .UsedRange.Columns(1).SpecialCells(xlCellTypeVisible)
If row.Value <> "ID" Then '***Column header
mainIDs(i) = row.Value
i = i + 1
End If
Next
If you use an array for filtering you have to cast the values to strings before.
As I understood you're adding integer/long values to the array. Autofilter can't work with this.
In addition you have to change your array to a string array mainIDs() as String or declare it as Variant.
For Each row In .UsedRange.Columns(1).SpecialCells(xlCellTypeVisible)
If row.Value <> "ID" Then '***Column header
mainIDs(i) = Cstr(row.Value) 'Cast values to string
i = i + 1
End If
Next
Then it should work, please let me know if it helped you.
If you use arrays as Criteria, you'll have to use a 1D array.
But then, you need to supply the Operator argument to actually filter all that is in the array.
Sample:
ActiveSheet.UsedRange.AutoFilter Field:=columnNum, _
Criteria1:=mainIDs, _
Operator:xlFilterValues
To know more about AutoFilter Method check MSDN.

How to reference an array and write to another array with more than one column per iteration

I am curious if I can copy multiple columns to a new array from an existing array in one iteration of a loop. Suppose we have the following general example:
Array1 contains 10,000 elements in column1, 10,000 elements in column2, and 10,000 elements in column 3, etc.
Let's say that I want a new array generated off that information, only I want only columns 1 and 2 populated. Can I do this by looping only once with a correctly dimensioned target array? For instance:
'Assume TargetArray has already been ReDimmed to the size of Array1 in the code prior
For i=0 to UBound(Array1)
TargetArray(x,1)= Array1(x,1)
TargetArray(x,2)=Array1(x,2)
Next
So can this be done in one step, or do I have to make a loop for each dimension I want to add to the array. Is there any speed savings by doing two operations per loop as stated above (assuming it works).
Thanks for all of your help!
Have you tried just using Range objects? I just made 100 values in columns A and B, and copy them to F and G. Or are you trying to plug values from the first three columns into an equation to give you values for the new two columns?
Sub CopyRange()
Dim Array1 As Range
Dim Array2 As Range
Set Array1 = Range("A1:B100")
Set Array2 = Range("F1:G100")
Array2.Value = Array1.Value
End Sub
Your example should work as what RubberDuck commented.
It is similar in below example which works at my end.
I can't fit it to comments so I have no choice to post it as answer.
Dim TargetArray ' declared as Variant type, not array of variants
ReDim TargetArray(0 To Ubound(Array1, 0), 0 To 1) ' for 2 columns
For i = 0 To Ubound(Array1, 1)
TargetArray(i, 0) = Array1(i, 0)
TargetArray(i, 1) = Array1(i, 1)
Next
Is this close to what you have? If so, then that should work.

Resources