Compare and count consecutive data in Excel - vba

I am trying to make an Excel macro to compare and count data from the same column.
Specifically, I want to count only if the a cell and the cell below the cell both have an absolute value less than 100.
End goal: Say the column below was the data that I have,
241.197
96.747
88.325
156
53.666
55.372
-45.667
-207.152
I want the macro to return a value of 2.
It would need to count
[96.747
88.325]
&
[53.666
55.372
-45.667]

Say you have column A with the data starting at A1
sub countTotal
dim i as integer
dim sum as double
dim count as integer
for i = 1 to Cells(Rows.Count, "A").End(xlUp).row
sum = Abs(Range("A" & i).Value) + Abs(Range("A" & i + 1).Value)
if sum < 100 then count = count + 1
next
msgbox count
end sub
Not tested. You should see if it counts the last value in your column + the empty one after, if it does, shorten the loop by 1.

Sub countTotal()
Dim i As Integer
Dim sum As Double
Dim count As Integer
For i = 1 To Cells(Rows.count, "A").End(xlUp).Row
If Abs(Range("A" & i).Value) < 100 And Abs(Range("A" & i + 1).Value) < 100 Then
count = count + 1
Else
count = count
End If
Next
MsgBox count
End Sub
Based on your code, this is what I came up with. It performs fine if the data looks like this:
120
70
-90
110
80
60
In which case the macro returns a value of 2.
The problem is that some of my data looks like this:
100
-80
90
70
-180
-190
Macro returns a value of 2 because it counts [-80 90] and [90 70]. But I want to make it so that when the absolute value of a consecutive set of data is all less than 100, macro counts it as 1. So ideally instead of returning 2 as the value, the macro should return 1 in this case.
Can you direct me in the right direction?
Thanks!

Related

Removing loops to make my VBA macro able to run on more data

in my data there are more than a thousand different six digit numbers that are reoccurring in no specific pattern. I need to find all six digit codes that exist in column A and for each number. For example 123456, then find summarize the value in column B for every row that has 123456 in column A. My code is not very effective but the runtime is not a problem if I run with only 10 rows. However, in the real data sheet there are 80 000 rows and my code will take to much time. Can someone help me edit my code but removing certain loops within loops or some stop conditions. I'm new to VBA and can't do it myself in the limited time I have.
Sub Test2()
Dim summa As Long
Dim x As Long
Dim condition As Boolean
Dim lRows As Long
Dim k1 As Integer
Dim i As Long
x = 1
Worksheets("Sheet1").Activate
For i = 100000 To 999999
k1 = 1
lRows = 10
condition = False
While k1 <= lRows
If Cells(k1, "A").Value = i Then
condition = True
End If
k1 = k1 + 1
Wend
If condition = True Then
Cells(x, "F").Value = Application.SumIf(Range("A:A"), CStr(i), Range("B:B"))
Cells(x, "E").Value = i
x = x + 1
End If
Next i
MsgBox "Done"
End Sub
You don't need VBA for this task. Follow these steps.
Insert a blank column C in a copy of the original data sheet.
Insert a SUMIF formula, like =SUMIF(A:A, A2, B:B) in C2 and copy all the way down.
Now all items 123456 will have the same total in column C
Copy column C and Paste Values (to replace the formulas with their values).
Delete column B.
Remove duplicates.

Replace cell value to contain percentage of total in excel

I have an excel sheet containing entities, their characteristics, a value for the characteristic and a total as follows:
Entity CHAR1 CHAR2 CHAR3 CHAR4 Total
1 10 20 5 5 40
2 5 100 30 25 160
3 25 25 10 20 80
Now I want to replace the values with percentages in which the total column is seen as 100% for each row seperately.
This would in this example result in:
Entity CHAR1 CHAR2 CHAR3 CHAR4
1 25 50 12,5 12,5
2 3,125 62,5 18,75 15,625
3 31,25 31,25 12,5 25
As my data-set is pretty big i'm wondering if there is a fast solution to do this? I get stuck because placing a formula in each cell will require calculating the new value using the old value in the cell itself. And using a new worksheet might give me some performance issues.
Thanks in advance
Run this sub and all should work as you asked (note that you need to define the TotalColumn column number (since it isn't evident in the example)
Sub MakePercent()
Dim Cell As Range, CalcRange As Range, TotalColumn As Variant
TotalColumn = 'Write the column number or letter here
Set CalcRange = ActiveSheet.Range(ActiveSheet.Cells(2,2), ActiveSheet.Cells(ActiveSheet.UsedRange.Rows.Count,TotalColumn - 1))
For Each Cell In CalcRange
Cell.Value = CDbl(Cell.Value) / CDbl(ActiveSheet.Cells(Cell.Row,totalColumn))
Next Cell
End Sub
Minor update from myself:
The macro as provided by RGA worked fine, until I expanded my data with some extra columns. It then caused excel to freeze and therefore i went looking for a new solution.
If found the following stackoverflow question and adding Application.ScreenUpdating = false to the beginning and Application.ScreenUpdating = true to the end of the macro resolved the freezing issue.
This leads to the following code:
Sub MakePercent()
Application.ScreenUpdating = False
Dim Cell As Range, CalcRange As Range, TotalColumn As Variant
TotalColumn = 'Write the column number or letter here
Set CalcRange = ActiveSheet.Range(ActiveSheet.Cells(2,2), ActiveSheet.Cells(ActiveSheet.UsedRange.Rows.Count,TotalColumn - 1))
For Each Cell In CalcRange
Cell.Value = CDbl(Cell.Value) / CDbl(ActiveSheet.Cells(Cell.Row,totalColumn))
Next Cell
Application.ScreenUpdating = True
End Sub

Inserting blank rows every x number of rows [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Insert row every X rows in excel
I have a large set of data (let's say it goes from B5 to J500 and let's say this range is named rngOutput). I am trying to go through this data and add 2 empty rows every x number of rows where x is a number the user specifies. For example if x is 10 then every 10 rows 2 new rows should be inserted. Conceptually, this is the code that should work:
For i = 1 to Number of rows in rngOutput
If i mod x = 0 Then
Insert 2 Rows
End If
Next i
However, when you insert 2 new rows, the row count changes and the formula messes up (i.e. it adds 2 rows after the first 10 rows, then it adds another 2 rows after the next 8 rows (since it counts those 2 new rows you added as actual rows) then it adds another 2 rows after the next 6 rows, etc.
I am trying to figure out a way to accomplish adding 2 new rows every x number of rows cleanly to avoid the above problem.
Thank you for the help and please let me know if you need additional clarification!
This is like Chris's only fleshed out. When inserting or deleting rows you have to work up from the bottom:
Sub InsertXRowsEveryYRows_WithMeaningfulVariableNames()
Dim NumRowsToInsert As Long
Dim RowIncrement As Long
Dim ws As Excel.Worksheet
Dim LastRow As Long
Dim LastEvenlyDivisibleRow
Dim i As Long
NumRowsToInsert = 2 'any number greater than 0
RowIncrement = 10 'ditto
Set ws = ActiveSheet
With ws
LastRow = .Range("A" & .Rows.Count).End(xlUp).Row
LastEvenlyDivisibleRow = Int(LastRow / RowIncrement) * RowIncrement
If LastEvenlyDivisibleRow = 0 Then
Exit Sub
End If
Application.ScreenUpdating = False
For i = LastEvenlyDivisibleRow To 1 Step -RowIncrement
.Range(i & ":" & i + (NumRowsToInsert - 1)).Insert xlShiftDown
Next i
End With
Application.ScreenUpdating = True
End Sub
Count from the bottom of the range
For i = Number of rows in rngOutput to 1 step -1
If i mod x = 0 Then
Insert 2 Rows
End If
Next i

Is it possible to give the count of maximum columns used by a particular row(s)

I have a Excel matrix as below:
PID# T1 T2 T3 T4 T5 T6 T7
11 1 1
14 1 1 1
21 1 1
41 1 1 1 1
71 1
88 1 1 1
PID# is nothing but the processes, all the processes has been composed of multiple tasks. But it is not mandatory that all processes should use all the T1 - T5 tasks. In such a scenario is it possible to get the PID# which used maximum tasks. 1 used to indicate that a task has been used or not. here the PID# 41 and 88 used maximum tasks say it is 5. I need only the maximum used column count and any of the row# which used that number of columns.
NOTE
here i have used 1 to tell there is data,but in reality there are different types of data. I need to find out which row used maximum columns.But one thing if any cells for a row is blank and it is to the left,should be in the count. say for example --
<> 1 <> 1 gives the count as 4
<> <> 1 <> will give the count as 3
1 1 <> will give the count as 2 ' here I used <> used to represent the no values
EDIT
Option Explicit
Dim ArrayListTaskDetails : Set ArrayListTaskDetails = CreateObject("System.Collections.ArrayList")
Dim i,colcount
i=2
Do while i < = objExcel1.Application.WorksheetFunction.CountA(ob.Rows(1))
colcount=objExcel1.Application.WorksheetFunction.CountA(ob.Rows(i))
ArrayListTaskDetails.Add(colcount)
i=i+1
Loop
ArrayListTaskDetails.Sort()
i=ArrayListTaskDetails.Count
MsgBox("HighestColumnNumner:" & ArrayListTaskDetails(i-1))
Problem:
I can't count the blank columns for rows which don't have the contiguous value. Thus count is not produced by me correctly.
EDIT1
Here the problem is still i can't count the left blank cells if any,as those are also to be considered as used column,in which other rows can have values.Thus need to find out the the right most column which has been used by a row after which no columns has been used by any rows. Hope I am able to clear what I am looking for:
Option Explicit
Dim objExcel1
Dim strPathExcel1
Dim objSheet1,objWB,ColCount
Dim ArrayListTaskDetails : Set ArrayListTaskDetails = CreateObject("System.Collections.ArrayList")
Set objExcel1 = CreateObject("Excel.Application")
strPathExcel1 = "D:\AravoVB\.xlsx"
Set objWB = objExcel1.Workbooks.open(strPathExcel1)
Set objSheet1 = objExcel1.ActiveWorkbook.Worksheets(1)
Do Untill count > objExcel1.Application.WorksheetFunction.CountA(objSheet1.Rows(1))
Range = objSheet1.("count:count")
ColCount=objExcel1.Application.WorksheetFunction.CountIf(Range,<> "")
ArrayListTaskDetails.Add(ColCount)
Loop
ArrayListTaskDetails.Sort()
MsgBox(ArrayListTaskDetails(ArrayListTaskDetails.Count - 1))
Thanks,
Still not convinced why Vikas answer is not working for you. Try this code please. It highlights the last max value. Only flaw is that it doesn't track all the PID that has same max value. I could improve the code if you need that as well.
Code:
Option Explicit
Sub getRealUsedColumns()
Dim rngInput As Range
Dim arrInput As Variant, arrRowTotal As Variant
Dim i As Integer, j As Integer, counter As Integer, iTemp As Integer
Dim iPID As Integer, maxRowNum As Integer
arrInput = Application.WorksheetFunction.Transpose(Sheets(3).Range("B3:I8").Value2)
ReDim arrRowTotal(LBound(arrInput, 2) To UBound(arrInput, 2))
For i = LBound(arrInput, 2) To UBound(arrInput, 2)
counter = 0
For j = LBound(arrInput) + 1 To UBound(arrInput)
If arrInput(j, i) <> "" Or Not IsEmpty(arrInput(j, i)) Then
counter = counter + 1
End If
Next j
'-- most recent max value (if you have two of the same, this doens't catch)
'-- you need to save in a proper array to catch multiple PIDs with same max value
If iTemp <= counter Then
iTemp = counter
iPID = arrInput(1, i)
maxRowNum = i
End If
arrRowTotal(i) = counter
Next i
'-- Row total into the sheet output
Sheets(3).Range("J3").Resize(UBound(arrRowTotal)) = _
Application.WorksheetFunction.Transpose(arrRowTotal)
'-- highlight the max total row.
With Sheets(3).Range("B3").Offset(maxRowNum - 1, 0).Resize(1, UBound(arrInput, 1) + 1)
.Interior.Color = 200
End With
End Sub
Results:
Excel is very powerful in calculating Matrix. I would use the Excel Formula instead of Code in order to calculate it. I would add a column in the right, which would add the total number of tasks used by a process, as shown in the matrix below.
A B C D E F G
1 PID T1 T2 T3 T4 T5 Total
2 #11 1 1
3 #14 1 1 1 3
4 #21 1 1 1 1 1 5
5 #41 1 1 2
Then I will write two Array Formulas to calculate the maximum number of tasks used by a process and the name of that process.
Formula to calculate maximum tasks used in the example: =SUM(IF($G$2:$G$5=MAX($G$2:$G$5),G2:G5,0))
Formula to find the pricess which used the maximum tasks:
=OFFSET(A1,SUM(IF($G$2:$G$5=MAX($G$2:$G$5),ROW(G2:G5)-1,0)),0,1,1)
Please note that I had mentioned that I used Array formulas. In order to add array formula in Excel, you need to enter formula and then press "Ctrl+Shift+Enter" to make that formula an array formula.
Hope this helps.
Vikas B
-----------------EDIT-----------------------------------------------------
Adding the code here. I just used the sample, as show in matrix and produced the correct result.
Sub FindMax()
'assuming column 1 is the task ID and Row one has the headings.
Const LastColumn As Integer = 7 ' you can use xl end to get the last used column in the range
Const LastRow As Integer = 5
Dim rowCounter As Integer
Dim prevValue As Integer
Dim rngToTotal As Range
Dim sht As Worksheet
Dim maxRowName As String
Dim value As Integer
Dim maxValue As Integer
Set sht = ActiveSheet
For rowCounter = 2 To LastRow
Set rngToTotal = sht.Range(sht.Cells(rowCounter, 2), sht.Cells(rowCounter, LastColumn))
value = WorksheetFunction.Sum(rngToTotal)
If value > prevValue Then
maxRowName = sht.Cells(rowCounter, 1).value
maxValue = value
End If
prevValue = value
Next rowCounter
MsgBox "Process name " & maxRowName & " = " & maxValue
End Sub

Calculating the sum of number difference within a for loop in vb.net

I have a dataset which includes some numbers, I want to calculate the sum of the difference in the numbers how do I do this?
For example my dataset looks like this:
Name Score
Luke 100
Adam 90
James 80
Peter 70
Mike 60
How do I calculate the sum of the difference within a “for loop” in vb.net such that it does something like this below:
(100 - 90) + (90 – 80) + (80 – 70) + (70 – 60) = 40
I tried to do this below, but i am not sure of how to add the difference:
Dim i as integer
For i = 0 to ds.tables(0).rows.count
ds.tables(0).Row(i).Item(1)
Dim diff = ds.tables(0).Row(i).Item(1) - ds.tables(0).Row(i+1).Item(1)
sum = ....
Next
Any help will be appreciated
You can try this,
Dim totalValue As Integer = 0
For index = 1 To ds.Tables(0).Rows.Count
totalValue += (CInt(ds.Tables(0).Rows(index - 1).Item(1)) - CInt(ds.Tables(0).Rows(index).Item(1)))
Next
You can use totalValue as your answer
First, you need to stop the loop before you reach the count, otherwise you will receive an exception.
Second, you need to add a special case for the first item:
' The sum of the differences
Dim wSumOfDifferences As Integer
' Start with a non-sensical value for the last value that we processed
Dim wLastValue As Integer = -1
For Each oRow As DataRow in ds.Tables(0).Rows
Dim wCurrValue As Integer
' Get the current value
wCurrValue = CInt(oRow.Item(1))
' If we are not working on the first item, calculate the difference between
' the current value and the last value
If wLastValue <> -1 Then
wSumOfDifferences += (wLastValue - wCurrValue)
End If
' Record the current value as the last value
wLastValue = wCurrValue
Next
Console.WriteLine("Sum = " & CStr(wSumOfDifferences))