Problem:
I am writing a macro to do some data input for me. These data reports all have the same format (date in column 1, value in column 2), except the order of the months of data change from client to client. Currently I have written the macro to grab the data from another sheet and bring it into the current sheet. But now I need to write something to take the data and get it into the correct format.
Example: This client is organized from Apr-Mar (again, it could be any 12 month combination) and I need to get it into Jan-Dec, regardless of year.
Before:
Apr-14 37,645
May-14 47,000
Jun-14 11,600
Jul-14 33,503
Aug-14 38,550
Sep-14 36,063
Oct-14 39,246
Nov-14 30,315
Dec-14 28,403
Jan-15 25,799
Feb-15 24,302
Mar-15 27,873
After:
Jan-15 25,799
Feb-15 24,302
Mar-15 27,873
Apr-14 37,645
May-14 47,000
Jun-14 11,600
Jul-14 33,503
Aug-14 38,550
Sep-14 36,063
Oct-14 39,246
Nov-14 30,315
Dec-14 28,403
Attempt at a Solution:
I am hesitant to post it as it's incomplete and would be hard to follow. All it does is parse the first date cell to get the first 3 letters corresponding to a month, then check against 12 if/elseif statements. There must be a better way to write it, I just can't think of it.
Any and all help is appreciated. I'm sure a shove in the right direction would help!
I ended up just creating a loop that looks for "Jan" and gets all the data from there.
'Loop to dynamically calendarize data
''Loop returns 2 arrays, length 12, index 0-11, "electic" and "heating" in Jan to Dec format
complete = False
For i = 9 To 20
If Left(target.Sheets("Sheet1").Cells(i, 1).Value, 3) = "Jan" Then
For j = 0 To (20 - i)
carryOver = i + j
electric(j) = target.Sheets("Sheet1").Cells(carryOver, 2).Value
heating(j) = target.Sheets("Sheet1").Cells(carryOver, 5).Value
Next j
complete = True
ElseIf complete = True Then
For k = j To 11
electric(k) = target.Sheets("Sheet1").Cells(9 + (k - j), 2).Value
heating(k) = target.Sheets("Sheet1").Cells(9 + (k - j), 5).Value
Next k
GoTo end_of_for
End If
Next i
end_of_for:
Related
I have data coming into Excel (from external source) that looks like:
**Column A** **Column B**
6/26/2017 null
Temperature 27
Pressure 5
6/27/2017 null
Temperature 29
Pressure 4
I would like to have it like this:
**Column A (Date)** **Column B (Temp)** **Column C (PSI)**
6/26/2017 27 5
6/27/2017 29 4
Since the data comes in via 'Refresh All', how can I take that and push it to columns like this?
If you are sure of the periodicity of your data, you may use the OFFSET function.
Add an auxiliary column with an crescent index;
fill the "column date" with =OFFSET($A$1; ($E2-1)*3; 0), where:
A1 refers to your first cell in your external data (6/26/2017)
E2 refers to your index, the cell where my function was applied being F2
If to be 'pushed' you would need something like VBA, though is possible with a formula (in C2, copied across to D2 and the pair copied down to suit):
=OFFSET(A2,1,1)
but that would then need to be converted to Values (eg with Paste Special) if the surplus column and rows are to be deleted. And this would not 'refresh' as easily as say a PivotTable.
Try working from the last date to the top.
Dim i As Long
With Worksheets(4)
For i = Application.Match(1E+99, .Range("A:A")) To 1 Step -3
.Cells(i, "C") = .Cells(i + 2, "B").Value
.Cells(i, "B") = .Cells(i + 1, "B").Value
.Cells(i + 1, "A").Resize(2, 1).EntireRow.Delete
Next i
.Cells(1, "A").EntireRow.Insert
.Cells(1, "A").Resize(1, 3) = Array("**Column A (Date)**", "Column B (Temp)", "**Column C (PSI)**")
End With
I would like to list the possible combinations of numbers 1 to 26 in columns A and B, in the following format:
1 1
1 2
1 3
1 4
...
1 25
1 26
2 1
2 2
2 3
...
etc
For Column A, I could have:
Range("A1:A26") = 1
Range("A27:A52") = 2
etc
But this seems long winded and there must be a better way of doing this.
I have found this code as an answer to another question which gives
Range("A1")=-500
Range("A1").Select
Selection.DataSeries Rowcol:=xlColumns, Type:=xlLinear, Date:=xlDay, _
Step:=1, Stop:=500, Trend:=False
as a way to list numbers sequentially but I would need to amend it to reach 26 and then start again from 1, all the way to the end of the list in Column A. How can I achieve this?
Try these formulas and then drag down as far as you need (row 676):
A1 =ROUNDUP(ROW()/26,0)
B1 =IF(MOD(ROW(),26)=0,26,MOD(ROW(),26))
A VBA solution as an alternative to the Excel formulas given in the previous reply. (Untested)
MyRow = 1 ' or wherever you want to start
MyCol = 1 ' or wherever you want to start
For A = 1 to 26
For B = 1 to 26
Cells(MyRow,MyCol).Value = A
Cells(MyRow,MyCol+1).Value = B
MyRow = MyRow + 1
Next B
Next A
The advantage of this approach instead of the formula described above is that it is not dependent on where you place the data. It can also be adapted if you want (e.g.) combinations of 5 to 24, or even A is 1 to 26 and B is 1 to 10.
But, the formula described in the previous answer is also a cool way of doing it.
If you changed:
For A = 1 to 26
For B = 1 to 26
to
For A = 1 to 26
For B = A to 26
then this would be useful for a non-directional combination (e.g. if [1,2] is the same as [2,1]).
So basically I will have a changing list of names entered like so
Deborah 9 30
Steven 4 22
Michelle 9 26
Michelle 8 30
Alice 10 28
John 3 21
David 7 23
David 9 26
David 7 24
Lucy 6 24
and my goal is to write a macros so that the names appear like this
Deborah 9 30
Steven 4 22
Michelle 17 56
Alice 10 28
John 3 21
David 23 73
Lucy 6 24
so all the rows with the same value for column 1 will be a sum of the values in the other column and consolidated to one row. The names are going to be changing, so I cant hardcode in IF something = "Michelle" it has to just be IF these rows = these other rows. I am trying to automate a tedious task at work, thanks for any suggestions!
If the duplicated names are in consecutive rows, then try this short macro:
Sub DeDup()
Dim N As Long, i As Long
N = Cells(Rows.Count, "A").End(xlUp).Row
For i = N To 2 Step -1
If Cells(i, 1) = Cells(i - 1, 1) Then
Cells(i - 1, 2) = Cells(i - 1, 2) + Cells(i, 2)
Cells(i - 1, 3) = Cells(i - 1, 3) + Cells(i, 3)
Range(Cells(i, 1), Cells(i, 3)).Delete Shift:=xlUp
End If
Next i
End Sub
You can create a distinct sorted list of names using an array formula with INDEX, MATCH, MAX and COUNTIF as described here:
http://www.get-digital-help.com/2009/04/14/create-a-unique-alphabetically-sorted-list-extracted-from-a-column/
Then you can just use a simple SUMIF function for each name in the result.
Just use a sumif formula. you can manipulate it to your needs. It will sum what you want in a given row. Or use an array if you would like.
I have an Excel file with several columns in it and many rows. One column, say A has ID numbers. Another column, say G has prices. Column A has repeating ID numbers, however not all numbers repeat the same amount of times. Sometimes just once, other times 2, 3 or several times. Each column G for that row has a unique price.
Basically, I need to average those prices for a given ID in column A. If each ID was repeated the same number of times, this would be quite simple, but because they are not I have to manually do my average calculation for each grouping. Since my spreadsheet has many many rows, this is taking forever.
Here is an example (column H is the average that I am currently calculating manually):
A ... G H
1 1234 3.00 3.50
2 1234 4.00
3 3456 2.25 3.98
4 3456 4.54
5 3456 5.15
11 8890 0.70 0.95
13 8890 1.20
...
So in the above example, the average price for ID# 1234 would be 3.50. Likewise, the average price for ID# 3456 would be 3.98 and for #8890 would be 0.95.
NOTICE how rows are missing between row 5 and 11, and row 12 is missing too? That is because they are filtered out for some other reason. I need to exclude those hidden rows from my calculations and only calculate the average for the rows visible.
Im trying to write a VBA script that will automatically calculate this, then print that average value for each ID in column H.
Here is some code I have considered:
Sub calcAvg()
Dim rng As Range
Set rng = Range("sheet1!A1:A200003")
For Each Val In rng
Count = 0
V = Val.Value '''V is set equal to the value within the range
If Val.Value = V Then
Sum = Sum + G.Value
V = rng.Offset(1, 0) '''go to next row
Count = Count + 1
Else
'''V = Val.Value '''set value in this cell equal to the value in the next cell down.
avg = Sum / Count
H = avg '''Column G gets the avg value.
End If
Next Val
End Sub
I know there are some problems with the above code. Im not too familiar with VBA. Also this would print the avg on the same line everytime. Im not sure how to iterate the entire row.
This seems overly complicated. Its a simple problem in theory, but the missing rows and differing number of ID# repetitions makes it more complex.
If this can be done in an Excel function, that would be even better.
Any thoughts or suggestions would be greatly appreciated. thanks.
If you can add another row to the top of your data (put column Headers in it) its quite simple with a formula.
Formula for C2 is
=IF(A2<>A1,AVERAGEIFS(B:B,A:A,A2),"")
copy this down for all data rows.
This applies for Excel 2007 or later. If using Excel 2003 or earlier, use AVERAGEIF instead, adjusting ranges accordingly
If you can't add a header row, change the first formula (cell C1) to
=AVERAGEIFS(B:B,A:A,A1)
In my way ..
Sub calcAvg()
Dim x, y, i, y2, t, Count, Mount As Integer
Dim Seek0 As String
x = 1 '--> means Col A
y = 1 '--> means start - Row 1
y2 = 7 '--> means end - Row 19
For i = y To y2
If i = y Then
Seek0 = Cells(i, x)
t = i
Count = Cells(i, x + 6)
Mount = 1
Else
If Cells(i, x) <> Seek0 Then
Cells(t, x + 7) = Count / Mount
Count = Cells(i, x + 6)
Mount = 1
t = i
Seek0 = Cells(i, x)
Else
Count = Count + Cells(i, x + 6)
Mount = Mount + 1
End If
End If
Next
End Sub
Hope this helps ..
The "B" column has occurence of time in it.Like these
A B
X4T00289 8/4/2011 3:12:07 AM
X4T00289 8/4/2011 3:15:07 AM
X4T00289 8/4/2011 3:18:20 AM
X4T00290 8/4/2011 3:12:37 PM
YCE00194 8/8/2011 5:12:17 AM
YCE00194 8/8/2011 5:14:07 AM
YCE00194 8/10/2011 10:12:06 PM
YCE00194 8/10/2011 10:15:16 AM
Z4W00109 8/12/2011 11:12:22 AM
Z4W00109 8/4/2011 11:58:07 AM
Z4W00109 8/4/2011 12:00:07 PM
I have taken a variant and dumped the range in it like these
var = activesheet.range("A1:B4000").value
QUESTION:
The problem is, I have to identify the consequent rows that has same ID in column A and which occured within 5 minutes and highlight them with color.Take a look at first 2 rows, They occured within 5 minutes and column A value is same for both but the 3rd row occurred after 5 minutes when compared to the first row, So that row should be ignored when highlighting .While coming back to the last 2 rows they also occured within 5 minutes, they should be highlghted with color as they occured within5 minutes. I think you got what i wanted to do. Any questions please comment and I will explain it more cleaner way.
MY APPROACH:
This is what i have tried
, I have used splitting some thing like these
temp = split(text," ")
and then compare temp(0) and temp(1) and temp(2) with consequent rows
temp(0) it has year date and month in it
temp(1) it has Time
temp(2) it has AM or PM
if temp(2) and temp(0) are equal for conesequent rows then this piece of code executes
temp_var=split(temp(1),":") again
again temp_var has temp_var(0)=hours temp_var(1)=minutes temp_var=seconds
Now I have to check hours if hours are equal then
I have to check for minutes like
(minutes - next row minutes) <= 5 then color it
This is what I have done.Im not getting any more better ideas to do it. I guess there might be some other easiest way in do it. may be some inbuilt functions which im not aware of So Let me know is this the only better way to do or any other better approach or algorithm to do it? like faster way to do it?Please help me with this
This is the Code you need, if you need any clarification or change comment here
Sub HighlightDiff()
Dim r As Integer
Dim i As Integer
Dim diff As Integer
Dim y As Integer
Dim m As Integer
Dim d As Integer
Dim h As Integer
r = 4000 ' Total No. of rows
For i = 1 To r
If (Trim(Cells(i, 1).Value) = Trim(Cells(i + 1, 1).Value)) Then
'd = Cells(i, 2).Value - Cells(i + 1, 2).Value
y = Year(Sheet1.Cells(i, 2)) - Year(Sheet1.Cells(i + 1, 2))
m = Month(Sheet1.Cells(i, 2)) - Month(Sheet1.Cells(i + 1, 2))
d = Day(Sheet1.Cells(i, 2)) - Day(Sheet1.Cells(i + 1, 2))
'h = Hour(Sheet1.Cells(i, 2)) - Hour(Sheet1.Cells(i + 1, 2))
If ((y + m + d) = 0) Then
diff = (Hour(Sheet1.Cells(i, 2)) * 60 + Minute(Sheet1.Cells(i, 2))) -
(Hour(Sheet1.Cells(i + 1, 2)) * 60 + Minute(Sheet1.Cells(i + 1, 2)))
If (diff > -5 And diff < 5) Then
Range(Cells(i, 1), Cells(i, 2)).Interior.ColorIndex = 3
End If
End If
End If
Next i
End Sub
here is the algorithm:
for each c in col B
minTime = MIN(col b where ref = current ref)
if c-minTime < 5 min then
change background
end if
next c
Note that you can get dateTime difference simply like this:
if range("onecell")-range("anothercell") < #00:05#
First off, it would be good to ensure that your datetime values in column B are formatted correctly. To do this:
Select all values in column B
Now press CTRL + 1
Select Custom and type in dd/mm/yyyy hh:mm:ss AM/PM
Now you can use the following code to loop through all id's in column A and highlight in red which ones have the same id and are within 5 mins of each other:
Sub WithinFiveMinutes()
Dim rngID As Range, id As Range, timeDiff As Long
Set rngID = Range("A1:A11") //Change for your id list e.g. A1:A4000
For Each id In rngID
If id = id.Offset(1, 0) Then
timeDiff = DateDiff("n", CDate(id.Offset(0, 1)), CDate(id.Offset(1, 1))) //"n" gives time difference in minutes...
If timeDiff >= -5 And timeDiff <= 5 Then
Range(id, id.Offset(0, 1)).Interior.ColorIndex = 3
Range(id.Offset(1, 0), id.Offset(1, 1)).Interior.ColorIndex = 3
End If
End If
Next id
End Sub