VBA code to find the sum of unique elements in a range - excel

I have 2 columns and need a VBA code to sum the values of unique elements in column "A", print the unique elements in column "D" and sum in column "E" :-
Name Value Name Sum
A 1 A 13
A 2 B 7
B 1 C 3
B 3
C 2
A 1
B 2
A 3
B 1
A 2
A 4
C 1
Can anyone help on this, this is what I tried :-
Sub CountSum()
Dim c As Collection, wf As WorksheetFunction, _
K As Long, N As Long, i As Long, _
v As Variant, d As Collection, y As Variant
Set c = New Collection
Set d = New Collection
Set wf = Application.WorksheetFunction
K = 2
N = Cells(Rows.Count, "A").End(xlUp).Row
On Error Resume Next
For i = 2 To N
v = Cells(i, "A").Value
y = Cells(i, "B").Value
c.Add v, CStr(v)
d.Add y
If Err.Number = 0 Then
Cells(K, "D").Value = v
Cells(K, "E").Value = wf.CountIf(Range("A:A"), v)
Cells(K, "F").Value = wf.Sum(Range("B:B"), y)
K = K + 1
Else
Err.Number = 0
End If
Next i
On Error GoTo 0
End Sub

Using a Dictionary:
Sub Tester()
Dim rng As Range, dict As Object
Set rng = Range(Range("A2"), Cells(Rows.Count, 1).End(xlUp)).Resize(, 2)
Set dict = SubTotals(rng, 1, 2)
DumpDict dict, Range("D1")
End Sub
Function SubTotals(rng As Range, colKey As Long, colVal As Long) As Object
Dim rv As Object, rw As Range, k, v
Set rv = CreateObject("scripting.dictionary")
For Each rw In rng.Rows
k = rw.Cells(colKey).Value
v = rw.Cells(colVal).Value
If Not IsError(k) And Not IsError(v) Then
If Len(k) > 0 And IsNumeric(v) Then
rv(k) = rv(k) + v
End If
End If
Next rw
Set SubTotals = rv
End Function
Sub DumpDict(dict As Object, rng As Range)
Dim i As Long, k
i = 0
For Each k In dict.keys
With rng.Cells(1)
.Offset(i, 0).Value = k
.Offset(i, 1).Value = dict(k)
End With
i = i + 1
Next
End Sub

next code works for me, I hope this will help you. This will work perfectly if at column A there are not blank cells between values.
Sub SUM()
Dim i, j, k As Integer
i = 2
j = 2
Range("D1").Value = "NAME"
Range("E1").Value = "VALUE"
'copy the first value of column A to column D
Range("D2").Value = Range("A2").Value
'cycle to read all values of column B and sum it to column E; will run until find a blank cell
While Range("A" & i).Value <> ""
'this check if actual value of column A is equal to before value of column A, if true just add the column B value to E
'else, look for the row in column D where is the same value of column A, if it doesn't exist code create the value
'in column D and E
If Range("A" & i).Value = Range("A" & i - 1).Value Then
Range("E" & j).Value = Range("E" & j).Value + Range("B" & i).Value
Else
flag = 1
While Range("D" & flag).Value <> ""
If Range("A" & i).Value = Range("D" & flag).Value Then
j = flag
Range("E" & j).Value = Range("E" & j).Value + Range("B" & i).Value
flag = Range("D1").End(xlDown).Row
Else
j = 0
End If
flag = flag + 1
Wend
If j = 0 Then
Range("D1").End(xlDown).Offset(1, 0).Value = Range("A" & i).Value
Range("E1").End(xlDown).Offset(1, 0).Value = Range("B" & i).Value
j = Range("E1").End(xlDown).Row
End If
End If
i = i + 1
Wend
MsgBox "End"
End Sub

Related

How to delete a row in a sheet based on values in the 3 columns

I have to delete a row if the of the column values of Column C, Column D , Column E of the same row is zero.
for example.
ColumnA Column B ColumnC ColumnD ColumnE
row1- abc xyz 0 abs abx
row2- wqe tuy 0 0 0
row3 uhiu khj kjh khk 0
here I have to delete the row 2 only because values of all column c , D , E are zero
Please help
A reverse loop should do the job. Try the below:
Option Explicit
Public Sub DeleteRows()
Dim i As Long, count As Long, lastRow As Long
' Replace Sheet1 with your sheetname
With ThisWorkbook.Worksheets("Sheet2")
' Change C with your most consistent column letter
' (a column that has data always to make sure there's no possibility to miss the last row due to empty cells)
lastRow = .Cells(.Rows.count, "C").End(xlUp).Row
' We do a reverse loop to not screw up the index
For i = lastRow To 2 Step -1
If .Range("C" & i).Value = "0" And .Range("D" & i).Value = "0" And .Range("E" & i).Value = "0" Then
.Range("C" & i).EntireRow.Delete
count = count + 1
End If
Next i
End With
' Display some message
If count > 0 Then
MsgBox "Done!" & vbCrLf & "Deleted " & count & " row(s).", vbInformation + vbOKOnly, "Success"
Else
MsgBox "No matches found for deletion", vbInformation + vbOKOnly, "Success"
End If
End Sub
Try,
Sub test()
Dim vDB, vR()
Dim Ws As Worksheet, toWs As Worksheet
Dim i As Long, n As Long
Dim j As Integer
Set Ws = ActiveSheet
vDB = Ws.UsedRange
For i = 1 To UBound(vDB, 1)
If vDB(i, 3) = 0 And vDB(i, 4) = 0 And vDB(i, 5) = 0 Then
Else
n = n + 1
ReDim Preserve vR(1 To 5, 1 To n)
For j = 1 To 5
vR(j, n) = vDB(i, j)
Next j
End If
Next i
Set toWs = Sheets.Add '<~~ set your sheet
With toWs
.Cells.Clear
.Range("a1").Resize(n, 5) = WorksheetFunction.Transpose(vR)
End With
End Sub
Try this code, fast and easy code.
Sub deleterow()
Dim i As Integer
i = 2
LastR = Cells(Rows.Count, 1).End(xlUp).row
For i = LastR To 2 Step -1
If Cells(i, 3).value = "0" And Cells(i, 4).value = "0" And Cells(i, 5).value = "0" Then
Cells(i, 1).EntireRow.delete
End If
Next i
End Sub

Microsoft Excel VBA Scripting: Recursive column matching

Sub NewMacro()
Dim endRow As Long
endRow = Sheet1.Range("A999999").End(xlUp).Row
For i = 1 To endRow
If Sheet1.Range("A" & i).Value = Sheet1.Range("F" & i).Value Then
Sheet1.Range("K" & i).Value = "Yes" Else
Sheet1.Range("K" & i).Value = "No"
End If
Next i
End Sub
This will compare column A with column F and displays the result in column K.
What I need is if this value is true, then like the above it should compare column B with column G, column C with column H and so on......and should display the results in next column. Please help.
I think you need a loop on the columns:
Sub NewMacro()
Dim endRow As Long
Dim i As Long
Dim c As Long
With Sheet1
endRow = .Range("A" & .Rows.Count).End(xlUp).Row
For i = 1 To endRow
For c = 1 To 5
If .Cells(i, c).Value = .Cells(i, c + 5).Value Then
.Cells(i, c + 10).Value = "Yes"
Else
.Cells(i, c + 10).Value = "No"
End If
Next c
Next i
End With
End Sub
This compares column A with F, column B with G, column C with H, column D with I and column E with J. Results are placed in columns K, L, M, N and O respectively.
This is equivalent to using the formula =IF(A1=F1,"Yes","No") in cell K1 and copying it across and down.
And a version which will update columns with "Yes", but stop as soon as it reaches a "No":
Sub NewMacro()
Dim endRow As Long
Dim i As Long
Dim c As Long
With Sheet1
endRow = .Range("A" & .Rows.Count).End(xlUp).Row
For i = 1 To endRow
For c = 1 To 5
If .Cells(i, c).Value = .Cells(i, c + 5).Value Then
.Cells(i, c + 10).Value = "Yes"
Else
.Cells(i, c + 10).Value = "No"
Exit For
End If
Next c
Next i
End With
End Sub

How do I merge a random number of cells with a blank cell in a column?

Example of my dataset:
blank
1
2
blank
3
4
5
blank
6
I want to merge all cells below a blank cell into the blank cell, but stop counting when it reaches the next blank cell.
End result should look like this, with the strings concatenated
12
345
6
I'm currently trying to create an array with 1s and 2s with 2 meaning its a blank cell, then counting the 1s and merging them. I don't know if this will work or if there is an easier way to do this.
This requires you to select the area you want to merge, starting with the first blank cell and ending with the last cell with a value. It will delete entire rows; not sure if that's what you wanted:
Sub MergeConstantsIntoEmpties()
Dim BlankCells As Excel.Range
Dim ConstantCells As Excel.Range
Dim i As Long
Dim MungedContents As String
With Selection
Set BlankCells = .SpecialCells(xlCellTypeBlanks)
Set ConstantCells = .SpecialCells(xlCellTypeConstants)
End With
For i = 1 To BlankCells.Areas.Count
If ConstantCells.Areas(i).Count = 1 Then
MungedContents = ConstantCells.Areas(i).Value
Else
MungedContents = Join(Application.WorksheetFunction.Transpose(ConstantCells.Areas(i).Value))
End If
BlankCells.Areas(i).Value = MungedContents
Next i
ConstantCells.EntireRow.Delete
End Sub
If we start with:
and run this macro:
Sub PileOn()
Dim N As Long, st As String
Dim i As Long, v As Variant
N = Cells(Rows.Count, "A").End(xlUp).Row
For i = N To 1 Step -1
v = Cells(i, 1).Value
If v <> "" Then
st = st & v
Cells(i, 1).Delete shift:=xlUp
Else
Cells(i, 1).Value = st
st = ""
End If
Next i
End Sub
We end up with:
EDIT#1:
To fix the order of the concatenated cells use this instead:
Sub PileOn()
Dim N As Long, st As String
Dim i As Long, v As Variant
N = Cells(Rows.Count, "A").End(xlUp).Row
For i = N To 1 Step -1
v = Cells(i, 1).Value
If v <> "" Then
st = v & st
Cells(i, 1).Delete shift:=xlUp
Else
Cells(i, 1).Value = st
st = ""
End If
Next i
End Sub
Here is my take on it.
Sub JoinBetweenTheLines()
Dim X As Long
X = 1
Do Until X >= Range("A" & Rows.Count).End(xlUp).Row
If Range("A" & X).text = "" Then
Range("A" & X).Delete xlUp
ElseIf Range("A" & X).Offset(1, 0).text = "" Then
X = X + 1
Else
Range("A" & X).Formula = Join(Application.Transpose(Range("A" & X & ":A" & X + 1)), "")
Range("A" & X + 1).Delete xlUp
End If
Loop
End Sub
I normally work backwards also but for this one went forwards.
I had memory processing in mind.
Sub merg()
Dim v As Long, w As Long, vVALs As Variant
With ActiveSheet 'reference the worksheet properly!
With .Range(.Cells(1, 1), .Cells(Rows.Count, 1).End(xlUp))
vVALs = .Cells.Value2
For v = LBound(vVALs, 1) To UBound(vVALs, 1)
If vVALs(v, 1) = vbNullString Then
For w = v + 1 To UBound(vVALs, 1)
If vVALs(w, 1) = vbNullString Then Exit For
vVALs(v, 1) = vVALs(v, 1) & vVALs(w, 1)
vVALs(w, 1) = vbNullString
Next w
End If
Next v
.Cells = vVALs
With .SpecialCells(xlCellTypeBlanks)
.Delete Shift:=xlUp
End With
End With
End With
End Sub

If a value in column M equals x then column A should Equal Column E

I need to start at the top of column L then go down row by row until the last row.
If the value in column L = 8 then copy the value from column E into column A.
If the value of column L = 7 then copy the value from column E into column B.
The error I receive is:
Method Range of Object_Global failed (1004)
Sub CopyVals()
Dim lngLoop As Long, lngRow As Long
Do Until IsEmpty(ActiveCell)
If Range("L" & lngLoop).Value = 8 Then
Range("E" & lngLoop).Copy Range("A" & lngLoop)
ElseIf Range("L" & lngLoop).Value = 7 Then
Range("E" & lngLoop).Copy Range("B" & lngLoop)
End If
ActiveCell.Offset(1, 0).Select
Loop
End Sub
Sub CopyVals()
Dim lngLoop As Long
lngLoop = 1
For lngLoop = 1 To Rows.Count
If Cells(lngLoop, 12).Value = "8" Then Cells(lngLoop, 1).Value = Cells(lngloop, 5).Value
If Cells(lngLoop, 12).Value = "7" Then Cells(lngLoop, 2).Value = Cells(lngloop, 5).Value
Next lngLoop
End Sub

Excel VBA splitting up rows

If in a cell of a table of data contains a value x > 1, I would like to copy and paste the row containing that cell "x" number of times. The rows would paste with x = 1 in the next available blank row.
TREVDAN 2
CENTRAL 3
GAL FAB 1
From this.
TREVDAN 1
TREVDAN 1
CENTRAL 1
CENTRAL 1
CENTRAL 1
GAL FAB 1
To looking something like this.
This will work for you.
Sub SpecialCopy()
'Assuming A and B columns source columns
Dim i As Long, k As Long
Dim j As Long: j = 1
For i = 1 To Cells(Cells.Rows.Count, 1).End(xlUp).Row
k = 1
Do While k <= Range("B" & i).Value
'Assuming C and D are destination columns
Range("C" & j).Value = Range("A" & i).Value
Range("D" & j).Value = 1
j = j + 1
k = k + 1
Loop
Next i
End Sub
Building off of the answer provided by #Jeanno, you can use the following if you want to paste the results directly over the top of the original table:
Sub SpecialCopy()
'Assuming A and B columns source columns
Dim i As Long, k As Long
Dim j As Long: j = 1
Dim ArrayLength As Long: ArrayLength = Application.WorksheetFunction.Sum(ActiveSheet.Range("B:B"))
ReDim MyArray(1 To ArrayLength) As String
For i = 1 To Cells(Cells.Rows.Count, 1).End(xlUp).Row
k = 1
Do While k <= Range("B" & i).Value
MyArray(j) = Range("A" & i).Value
j = j + 1
k = k + 1
Loop
Next i
For Each MyCell In Range("a1:a" & ArrayLength)
MyCell.Value = MyArray(MyCell.Row())
MyCell.Offset(0, 1).Value = 1
Next MyCell
End Sub

Resources