I have a worksheet of athletes whose names appear all in one row. I want to grab all of the data underneath these names (aka the whole columns) so that I can manipulate the data. My issue is that I'm not familiar with available methods or functions in Excel VBA so I have only gone as far as this:
Dim MyArray(0 to 9) as String
MyArray(0) = "Molly"
MyArray(1) = "Jane"
MyArray(2) = "Louis"
MyArray(3) = "Omar"
MyArray(4) = "Wendy"
MyArray(5) = "Greg"
MyArray(6) = "Tina"
MyArray(7) = "Andrew"
MyArray(8) = "Jen"
MyArray(9) = "Lucy"
I'm thinking of creating a script that will look through all the names and select the columns whose names match the values in the Array.
EDIT: I've uploaded an example WS here for reference (please forgive me if this is not according to SO standards, still trying to figure out how this site works and I don't have enough rep to post images :D). I'm interested in manipulating the numbers in the "Total" row, and need to showcase it (along with the specific names that it belongs to). I want to iterate this manipulation over all instances that these names pop up in the WS though, so a loop of sorts would be necessary
Thanks again for the tips/help!
You can loop accross the columns. The code below assumes the columns & your array are in the same order and that you are interested in the first 10 rows of each column of sheet 1.
With Worksheets (1)
For x = 1 to (UBound (MyArray) +1)
' Select column
Range (.Cells (1, x), .Cells (10, x)).Select
' Do whatever you want with the data
'
Next x
End With
You can make this more intelligent using If statements to check whether the first cell in each column matches a name etc. but at least it's a start!
Related
I would like to find the text "Currency" in columns A or B, store all the currencies listed under Currency. Same process for Amount (Can be in an column)
Store values in an array. Then paste in Output Sheet. The currencies will already be listed in Output sheet in 1st row of the sheet. However if it is a new currency then the code should find last used cell in row 1 and add it. The value of Amount should be added to Output sheet against the currency and ID number also copied from the Source sheet.
I have some code.
Public Sub loopRow()
Dim curArray As Variant
Dim listarray As Variant
Dim cnt As Long
'Find Currency
Dim rgFound As Range
Set rgFound = Range("A:B").Find("Currency")
'Find last used row
curArray = Cells(rgFound.Address).End(xlUp).Row
'Transpose list of currecny from the row down from the word Currency that it has found
listarray = Application.Transpose(Cells(Rows, curArray).End(xlUp)).Row
For cnt = LBound(curArray) To UBound(curArray)
curArray(cnt) = curArray(cnt)
Next cnt
For cnt = LBound(curArray) To UBound(curArray)
'Debug.Print curArray(cnt)
'Copy and paste into Sheet under the correct curreny, if new currency then add this in row A
Next cnt
End Sub
Whilst you need to understand your question is unanswerable as is, I'll do my best to help.
The problem we have is not seeing the source sheet the way you do, as we can't see it at all. You say you have the word Currency in columns A or B or both, and an ID column somewhere, and Amount values everywhere. That's tricky source data. If as is more likely, the ID is in a specific column and the amounts are in a set of columns, then we'd have a chance.
Your question outlines the basic steps you'd want to take pretty well, so you're off to a good start.
However you can do all of the work without VBA, certainly if I'm right about the Source data. Create yourself a working sheet, or multiple working sheets. Definitely one to sort out the full list of currencies. Grab a copy of columns A and B (by formulae) and then have the working sheet go through line by line and use logic to build the list. Spreadsheets are great at this.
Once you have the list, use it as row headers on your Output sheet and use sumifs to get the values. I am not sure how the IDs would fit in, but if they were to be your row headings, then do the same as the above to get the list of unique ids and link them into your Output page in column A. Your sumifs can handle that.
That will hardly tell you all you need to know, but if you work it out you'll have learned a lot about Excel and when you need to go into VBA.
If you'd rather do it with VBA, break down each step until it works, and then go onto the next one.
And if you want more help, paste your data in here. Anonymise it first if you need to.
I am trying to find a method to loop through rows in a named table, copying each row over to another table and adding a value in a blank field on the end of each row which sequences the dates between a date span.
I came across code which can separate a date span successfully into rows, but have been having trouble creating a loop to go through each row of data and copying the rest over.
Example of data from table (w/ headers):
Table Name: TblOGCalendar
Sheet Name: OGCalendarData
Should be copied over to look like the following:
Table Name: TblR2Calendar
Sheet Name: R2CalendarData
This also has implications for another project that I am working on, in which they are wanting staff hours tracked and projected for Project work.
is is by no means an answer but more suited to help you learn stuff
Loops through excel files can be done in various ways - some good and some bad. Just depends on your skill level & comfort level with working with code.
Im only going to outline 2 methods
method #1 - Looping through the rows/columns themselves. I dont like this method as its bad practice - interacting with the applications objects is aperformance killer.
dim rng as range, rcell as range
' you have to tell the compiler where stuff is at
' this is important and a commmon mistake that causes quesitons her eon SO
set rng = Thisworkbook.worksheets("Yoursheetname").Range("yourrange")
for each rcell in rng.Cells
'rcell is the current cell in the range you're looping through.
'Will physically loop through cells top to bottom, left to right
' do some processing.
next rcell
method #2 - Working in memory with arrays. This is the preferred method and the one you should get good at if you plan on using excel-vba more often in the future.
dim arr as variant ' you need this for dumping sheet to arrays
dim i as long, j as long
arr = THisworkbook.Worksheets("yoursheet").UsedRange
' there are many ways to get the desired range of a sheet - pick your favorite (after researching), and use that.
' the ubound and lbound functions literally mean upper and lower. It basically says for i equal beginning of array dimension to last.
' the number dictates what dimension of the array you want to loop through. Excel ranges are mutlidimensional by default. 1 = rows, 2 = columns
for i = LBound(arr,1) to UBound(arr,1)
for j = LBound(arr,2) to UBound(arr,2)
' do some processing
' array values can be accessed through this methods
' arr(i,j)
' arr(i, x) x being a number, like if you know i want column 7 of current iteration/row
' arr(i+1, j-1) plus values move down, or to the right (depending on dimension) while negative value go up or left (depending on dimension)
next j
next i
'to put stuff back on your sheet after processing
thisworkbook.worksheets("yoursheet").range("yoursheet").value = arr
this should get you going on figuring things out for yourself
I've run into a bit of a road block. I get a .PDF output from an accounting program and copy/paste the data into excel, then convert text to columns. I am trying to match the GL code with the totals for that specific account. Columns A, B, and C show the state of my data prior to sorting it, and the lines under Intended Output show how I would like the data to output.
I am trying to automate this process, so I can paste data into columns A, B, & C in the raw format and have it automatically spit out the required numbers in the format of the Intended Output. The GL codes remain the same, but the numbers and the number of rows will change. I've color coded them for ease of review.
Thank you very much in advance!
Using a combination of the following formulas you can create a list of filtered results. It works on the principal that you Data1 text that you want to pull is the only text with a "-" in it, and that the totals you are pulling from Data2 and Data3 are the only numbers in the column. Any change to that pattern will most likely break the system. Note the formulas will not copy formatting.
IFERROR
INDEX
AGGREGATE
ROW
ISNUMBER
FIND
Lets assume the output will be place in a small table with E2 being the upper left data location.
In E2 use the following formula and copy down as needed:
=IFERROR(INDEX(A:A,AGGREGATE(15,6,ROW($A$1:$A$30)/ISNUMBER(FIND("-",$A$1:$A$30)),ROW(A1))),"")
In F2 use the following formula and copy to the right 1 column and down as needed:
=IFERROR(INDEX(B:B,AGGREGATE(15,6,ROW($A$1:$A$30)/ISNUMBER(B$1:B$30),ROW(A1))),"")
AGGREGATE performs array like calculations. As such, do not use full column references such as A:A in it as it can lead to excess calculations. Be sure to limit it to the range you are looking at.
Try this procedure:
Public Sub bruce_wayne()
'Assumptions
'1. Data spreadsheet will ALWAYS have the structure shown in the question
'2. The key word "Total" (or whatever else it might be) is otherwise NOT found
' anywhere else in the 1st data column
'3. output is written to the same sheet as the data
'4. As written, invoked when data sheet is the active sheet
'5. set the 1st 3 constants to the appropriate values
Const sData2ReadTopLeft = "A1" 'Top left cell of data to process
Const sData2WriteTopLeft = "J2" 'Top left cell of where to write output
Const sSearchText = "Total" 'Keyword for summary data
'*******************
Const sReplaceText = "Wakanda"
Dim r2Search As Range
Dim sAccountCode As String
Dim rSearchText As Range
Dim iRowsProcessed As Integer
Set r2Search = Range(sData2ReadTopLeft).EntireColumn
sAccountCode = Range(sData2ReadTopLeft).Offset(1, 0).Value
iRowsProcessed = 0
Do While Application.WorksheetFunction.CountIf(r2Search, sSearchText) > 0
Set rSearchText = r2Search.Find(sSearchText)
Range(sData2WriteTopLeft).Offset(iRowsProcessed, 0) = sAccountCode
Range(sData2WriteTopLeft).Offset(iRowsProcessed, 1) = rSearchText.Offset(0, 1).Value
Range(sData2WriteTopLeft).Offset(iRowsProcessed, 2) = rSearchText.Offset(0, 2).Value ' add this if there are more summary columns to return
'last two lines could be collapsed into a single line; at the expense of readability..
rSearchText.Value = sReplaceText 'so that next search will find the next instance of the trigger text
iRowsProcessed = iRowsProcessed + 1
sAccountCode = rSearchText.Offset(1, 0).Value
Loop
r2Search.Replace what:=sReplaceText, Replacement:=sSearchText
End Sub
I have a large table that only shows a single type of information: whether or not a species of plant was present at a particular study site. I have 500+ species listed in the first column, and 30 sites as column names. The table is populated with a simple "Y" or "N" to show presence. Example:
Scientific Name Old Wives Beach Dadi Orote N Airstrip
Abelmoschus moschatus N N N
Abrus precatorius Y N Y
Abutilon indicum N N N
However, the species list contains some species that do not occur at any sites, rendering a row full of "N"s, like the 1st and 3rd rows in the example above. I need to delete those rows in order to make the table more manageable.
Is there any way to achieve this without a long IF AND statement?
Inspired by pnuts' comment, in a new column, use the a COUNTIF() formula. For example, =COUNTIF(B2:AE2,"Y"), assuming the row/column headers are in row 1 and column A and the data is in the range B2:AE501+.
If you then select the entire range, including the headers and the new formula column and add filters, then you can select only the rows where the count of Y's is 0. Once you have only the 0's showing, you can select the entire rows and delete them (using Right-Click, Delete) without effecting the non-zero rows.
At this point, if you no longer need the count column, you can turn off the filter and delete the column but I wouldn't be surprised if you find the count comes in handy for some other reason.
Alternately, you could just use the filter to HIDE the 0 rows rather than delete them and that way to don't remove the data altogether but it's no longer in your way.
The code below is one way to do this, assuming there are no gaps in the data. The animated gif steps through to demonstrate how it works. You should remove the .select statements once you understand it.
Sub deleteIfAllN()
Dim plantR As Range, cell As Range, allN As Boolean
Set plantR = Range("A2")
While plantR <> ""
plantR.Select
Set r = plantR.Offset(0, 1)
allN = True
Do
r.Select
If r <> "N" Then
allN = False
Exit Do
End If
Set r = r.Offset(0, 1)
Loop Until r = ""
Set plantR = plantR.Offset(1, 0)
Rows(plantR.row - 1).Select
If allN Then Rows(plantR.row - 1).Delete
Wend
End Sub
You can use the Advanced Filter
Set up your data and criterion area as below
For the example you posted, the formula would be:
=COUNTIF($B8:$D8,"N")<>3
For 30 columns, just modify the range and the count.
Before
After
I chose to filter in place
Note that there is also an option to Copy to another location which would place the results of the filter in another location.
Please have a look at this table, which I have named "Tasks":
It is a very basic GANTT chart-like table. Using VBA I use data from this table in order to perform some tasks in other Worksheets.
I have a For loop which loops through each row like this:
For i = 1 To Range("Tasks").Rows.Count
Worksheets("Calendar").Cells(i,2).Value = Range("Tasks").Cells(i,2)
End For
There are many other operations within the For loop, but that goes beyond the scope of my question. Basically what this does is that it loops through the entire table and performs various operations and calculations (where applicable) which results in populating other cells in other worksheets.
My question is this:
Since all columns in the table are labeled, I would like to somehow reference the Column name instead of column number in the loop, if it is possible of course.
For example:
Worksheets("Calendar").Cells(i, 2).Value = Range("Tasks").Cells(i, "Title")
This helps for code readability since then I would know that this references the "Title" column, instead of going back and forth to see which column is e.g. the number "2".
I know that this kind of reference can be done in Excel by using
=Tasks[Title]
(e.g. This expression can be used for Data Validation)
Is it possible to reference columns like this? I am relatevely new to VBA, so I'm not quite sure.
Looking forward for your answer.
if it's an Excel Table, then you can use
Dim lo As ListObject
Dim col As ListColumn
Dim r As Range
Set lo = ActiveSheet.ListObjects("Tasks")
Set col = lo.ListColumns.Item("Title")
r = col.DataBodyRange
For i = 1 To Range("Tasks").Rows.Count
Worksheets("Calendar").Cells(i,2).Value = r.Cells(i)
End For