I was previously using a macro which found the first blank line in a workbook and then put tags in the next 9 columns. This was working well for a project however i've now encountered issues in that macro doesn't always find the exact blank row i want (maybe because of formatting i'm not sure)
This was my code for that idea:
Sub SetupTags(pintNumFeatures As Integer, pintNumRecords As Integer, pintSubGroupSize As Integer)
Dim lngRow As Long
Dim lngCol As Long
Dim lngTotal As Long
Dim lngCell As Long
Dim lngDataRow As Long
Dim lngDataCol As Long
Dim lngFirstRow As Long
lngFirstRow = FindFirstBlankRow
lngRow = lngFirstRow
lngCol = 9
lngTotal = pintNumFeatures * pintNumRecords
lngDataCol = 1
lngDataRow = 1
For lngCell = 1 To lngTotal
ActiveWorkbook.Worksheets(1).Cells(lngRow, lngCol).Value = "[act]{rowcol:" & lngDataRow & "," & lngDataCol & "}"
lngCol = lngCol + 1
If lngCol > 13 Then
lngRow = lngRow + 1
lngCol = 9
End If
lngDataRow = lngDataRow + 1
If lngDataRow > pintNumRecords Then
lngDataCol = lngDataCol + 1
lngDataRow = 1
End If
Next lngCell
'now figure out the column specific stuff
Dim intPartRows As Integer
Dim intPartRow As Integer
Dim intFeature As Integer
Dim intRecordNumber As Integer
intPartRows = CInt(pintNumRecords / 5)
lngRow = lngFirstRow
lngCol = 1
intRecordNumber = 1
For intFeature = 1 To pintNumFeatures
For intPartRow = 0 To intPartRows - 1
ActiveWorkbook.Worksheets(1).Cells(lngRow, 1).Value = "[part_" & intFeature & "]"
ActiveWorkbook.Worksheets(1).Cells(lngRow, 2).Value = "[dim_" & intFeature & "]"
ActiveWorkbook.Worksheets(1).Cells(lngRow, 3).Value = "[date]{Row:" & intRecordNumber & "}"
ActiveWorkbook.Worksheets(1).Cells(lngRow, 4).Value = "[date]{Row:" & intRecordNumber & "}"
ActiveWorkbook.Worksheets(1).Cells(lngRow, 5).Formula = "=AVERAGE(I" & lngRow & ":M" & lngRow & ")"
ActiveWorkbook.Worksheets(1).Cells(lngRow, 6).Formula = "=MAX(I" & lngRow & ":M" & lngRow & ") - MIN(I" & lngRow & ":M" & lngRow & ")"
ActiveWorkbook.Worksheets(1).Cells(lngRow, 14).Value = "[tf1]{Row:" & intRecordNumber & "}"
ActiveWorkbook.Worksheets(1).Cells(lngRow, 15).Value = "[tf2]{Row:" & intRecordNumber & "}"
ActiveWorkbook.Worksheets(1).Cells(lngRow, 16).Value = "[tf3]{Row:" & intRecordNumber & "}"
ActiveWorkbook.Worksheets(1).Cells(lngRow, 17).Value = "[tf4]{Row:" & intRecordNumber & "}"
ActiveWorkbook.Worksheets(1).Cells(lngRow, 18).Value = "[tf5]{Row:" & intRecordNumber & "}"
ActiveWorkbook.Worksheets(1).Cells(lngRow, 19).Value = "[tf6]{Row:" & intRecordNumber & "}"
ActiveWorkbook.Worksheets(1).Cells(lngRow, 20).Value = "[tf7]{Row:" & intRecordNumber & "}"
lngRow = lngRow + 1
intRecordNumber = intRecordNumber + 5
Next intPartRow
Next intFeature
End Sub
Function FindFirstBlankRow() As Long
Dim lngRow As Long
Dim lngFound As Long
'we need to check for blanks and not shaded to determine the actual last used row since the xlSpecialCells is not always accurate
'change this for each stage maybe 27 is the first empty row of stage 2 onwards we cannot have any empty rows passed this point'
For lngRow = 27 To 1000
If Sheet1.Cells(lngRow, 2).Value = "" Then
lngFound = lngRow
Exit For
End If
Next lngRow
FindFirstBlankRow = lngFound
End Function
Sub ReAddTags() 'pintNumFeatures As Integer, pintNumRecords As Integer, pintSubGroupSize As Integer)
Dim lngRow As Long
Dim lngFirstRow As Long
lngFirstRow = FindFirstBlankRow
lngRow = lngFirstRow
ActiveWorkbook.Worksheets(1).Cells(lngRow, 1).Value = "[All Feature Numbers]"
ActiveWorkbook.Worksheets(1).Cells(lngRow, 2).Value = "[ALL EXTRA INFO]"
ActiveWorkbook.Worksheets(1).Cells(lngRow, 4).Value = "[ALLLABELS]"
ActiveWorkbook.Worksheets(1).Cells(lngRow, 6).Value = "[allnoms]"
ActiveWorkbook.Worksheets(1).Cells(lngRow, 7).Value = "[FEATURE_SOURCES]"
ActiveWorkbook.Worksheets(1).Cells(lngRow, 9).Value = "[ACTROWS]"
End Sub
So i need to approach it a different way i have constant across the workbook of the word "Sequence" it always sits 1 line above the where i want to reintroduce these tags so i'm looking for something like this
• Find the next Sequence Text (this is always 1 line above where I want to put the tags back in)
• Then move one line below and add the tags back in
• There would need to be some kind of IF statement saying that if there is text in this line then skip to the next sequence text (this would stop it putting tags back into stages that have already been populated with data)
I can find some other code which does a find and replace but nothing as advanced to skip a line and also populate this IF statement
Sub test()
Dim rngColumn As Range
Dim rngCell As Range
Set rngColumn = Worksheets("Sheet1").Columns("H")
For Each rngCell In rngColumn.Cells
If Trim(rngCell) <> "" Then
If Trim(rngCell) = "815" Then
rngCell.Value = "'0815"
End If
End If
Next rngCell
Set rngColumn = Nothing
Set rngCell = Nothing
End Sub
Any guidance would be greatly appreciated
For moving to the next available row in a column you could use:
Selection.End(xlDown).Select
ActiveCell.Offset(1, 0).Range("A1").Select
Related
New user here who is also very new to Excel VB.
At the moment, I have a macro which does what you see here.
Essentially, I have 2 columns which can sometimes have cells which contain vertically stacked lines of data in each cell. Each of those lines is split out and put into newly inserted rows below (one line of data in the cell per row).
The problem I am having now, is that while the new rows now contain data in the two columns which had to be split (34 and 35), the remaining cells are empty. I am having trouble bringing the remaining 38 columns down into the newly-created rows. You can see what I mean in the image I posted. Two new rows were created and I need to fill them with the content of row 1 (fill in to the shaded area).
Here is my code right now. The part that is commented out is me trying to fill the empty space. The un-commented code does what you see in the image.
Sub main()
Dim iRow As Long, nRows As Long, nData As Long
Dim IDVariables As Range
Dim arr As Variant
With Worksheets("UI").Columns("AH")
nRows = .Cells(.Rows.Count, 1).End(xlUp).Row
For iRow = nRows To 2 Step -1
With .Cells(iRow)
arr = Split(.Value, vbLf)
nData = UBound(arr) + 1
If nData > 1 Then
.EntireRow.Offset(1).Resize(nData - 1).Insert
.Resize(nData).Value = Application.Transpose(arr)
.Offset(, 1).Resize(nData).Value = Application.Transpose(Split(.Offset(, 1).Value, vbLf))
'Set IDVariables = Range("A" & iRow & ":AG" & iRow)
'IDVariables.Select
'Selection.Copy
'Range("A" & (iRow + 1) & ":A" & (iRow + nData -1)).Select
'Selection.Paste
End If
End With
Next iRow
End With
End Sub
Any help would be very much appreciated.
Thanks!
Tested and working fine....
Option Explicit
Sub ReCode()
Dim ws As Worksheet: Set ws = ThisWorkbook.Sheets("Sheet1")
Dim LR As Long, i As Long, arr
LR = ws.Range("AH" & ws.Rows.Count).End(xlUp).Row
For i = LR To 2 Step -1
If InStr(ws.Range("AH" & i), vbLf) Then
ws.Range("A" & i + 1).EntireRow.Insert xlUp
ws.Range("A" & i).EntireRow.Copy ws.Range("A" & i + 1)
arr = Split(ws.Range("AH" & i), vbLf)
ws.Range("AH" & i) = arr(0)
ws.Range("AH" & i + 1) = arr(1)
arr = ""
End If
Next i
End Sub
I'm late doing this but I figured it out. I'll post my solution for anyone who has a similar problem.
Sub main()
Dim iRow As Long, nRows As Long, nData As Long
Dim arr As Variant
Dim IDVariables, Comments, AllocationCheck As Range
Application.ScreenUpdating = False
With Worksheets("PRM2_Computer").Columns("AH")
nRows = .Cells(.Rows.Count, 1).End(xlUp).Row
For iRow = nRows To 2 Step -1
With .Cells(iRow)
arr = Split(.Value, vbLf)
nData = UBound(arr) + 1
If nData = 1 Then
Range("AI" & iRow) = 1
Range("AK" & iRow) = "Single Industry"
End If
If nData > 1 Then
.EntireRow.Offset(1).Resize(nData - 1).Insert
.Resize(nData).Value = Application.Transpose(arr)
.Offset(, 1).Resize(nData).Value = Application.Transpose(Split(.Offset(, 1).Value, vbLf))
.Offset(, 2).Resize(nData).Value = Application.Transpose(Split(.Offset(, 2).Value, vbLf))
Set Comments = Range("AL" & iRow & ":AM" & iRow)
Comments.Copy Range("AL" & (iRow + 1) & ":AL" & (iRow + nData - 1))
Set AllocationCheck = Range("AK" & (iRow) & ":AK" & (iRow + nData - 1))
AllocationCheck.Value = Application.Sum(Range("AI" & iRow & ":AI" & (iRow + nData - 1)))
Set IDVariables = Range("A" & iRow & ":AG" & iRow)
IDVariables.Copy Range("A" & (iRow + 1) & ":A" & (iRow + nData - 1))
End If
End With
Next iRow
End With
End Sub
I have data for the year 2019 to 2021 and from 2016 to 2018. I want to combine the data and the KeyNumbers to follow, i was thinking it is best via VBA. But i am clueless on how to do it, so far i move the data from one sheet to this one, and here i have the data collected. But the years is seperated. I need it to be as shown from row R to T. This would be a big help for me, because i have 65 of these sheets. So a simple VBA would be so much help!
Thanks in advance
I tried to write VBA. It is getting there but mixing it up as result
Sub x()
Dim lngDataColumns As Long
Dim lngDataRows As Long
lngDataColumns = 2
lngDataRows = 20
For t = 1 To lngDataRows
Range("n2").Offset(((t - 1) * lngDataColumns) - 1, 0).Resize(lngDataColumns, 1).Value = _
Application.Transpose(Range("g24:h24").Offset(t).Value)
Range("o2").Offset(((t - 1) * lngDataColumns) - 1, 0).Resize(lngDataColumns, 1).Value = _
Application.Transpose(Range("i24:j24").Offset(t).Value)
Next t
End Sub
Sub y()
Dim lngDataColumns As Long
Dim lngDataRows As Long
lngDataColumns = 3
lngDataRows = 20
Range("p2").Offset(((t - 1) * lngDataColumns) - 1, 0).Resize(lngDataColumns, 1).Value = _
Application.Transpose(Range("h5").Offset(t).Value)
End Sub
You could try:
Option Explicit
Sub test()
Dim LastrowH As Long, Year As Long, i As Long, LastrowR As Long
Dim Amount As Double
Dim Key As String
With ThisWorkbook.Worksheets("Sheet1")
LastrowH = .Cells(.Rows.Count, "H").End(xlUp).Row
For i = 2 To LastrowH
'Check if Key start from DR (we assume that anything start with DR is key we need)
If Left(.Range("H" & i).Value, 2) = "DR" Then 'Remove this line
Key = .Range("H" & i).Value
Amount = .Range("L" & i).Value
Year = .Range("M" & i).Value
LastrowR = .Cells(.Rows.Count, "R").End(xlUp).Row
.Range("R" & LastrowR + 1).Value = Key
.Range("S" & LastrowR + 1).Value = Amount
.Range("T" & LastrowR + 1).Value = Year
If Year = 2018 Then
.Range("R" & LastrowR + 2 & ":R" & LastrowR + 4).Value = Key
.Range("S" & LastrowR + 2 & ":S" & LastrowR + 4).Value = Amount
.Range("T" & LastrowR + 2).Value = Year + 1
.Range("T" & LastrowR + 3).Value = Year + 2
.Range("T" & LastrowR + 4).Value = Year + 3
End If
End If 'Remove this line
Next i
End With
End Sub
if you want to remove the DR ( if statement) remove the lines with 'Remove this line at the end.
I am building on some code, partly cut and paste from other posts. I need to concatenate with a VBA code keeping the format and running through rows to output in last cell in each row. (Can't paste image) so hope description is clear:
In A1:D1 values are RED,BLUE,GREEN
In A2:D2 Values are YELLOW,PURPLE,ORANGE
OUTPUT IN E1 should concatenate these values, keeping font colour. Each value should have "ALT ENTR" to give line break.
Next row should be displayed in E2, and so on
'************************************************************************************
Sub test()
Dim rng As Range: Set rng = Application.Range("a1:c1") 'Not yet looping
Dim row As Range
For Each row In rng.Rows
'Debug.Print col.Column
Call concatenate_cells_formats(Cells(1, 4), rng) 'Not yet looping
Next row
End Sub
Sub concatenate_cells_formats(cell As Range, source As Range)
'Anon
Dim c As Range
Dim i As Integer
i = 1
With cell
.Value = vbNullString
.ClearFormats
For Each c In source
.Value = .Value & " " & Trim(c)
Next c
.Value = Trim(.Value)
For Each c In source
With .Characters(Start:=i, Length:=Len(Trim(c))).Font
.Name = c.Font.Name
.FontStyle = c.Font.FontStyle
.Size = c.Font.Size
.Strikethrough = c.Font.Strikethrough
.Superscript = c.Font.Superscript
.Subscript = c.Font.Subscript
.OutlineFont = c.Font.OutlineFont
.Shadow = c.Font.Shadow
.Underline = c.Font.Underline
.ColorIndex = c.Font.ColorIndex
End With
.Characters(Start:=i + Len(c), Length:=1).Font.Size = 1
i = i + Len(Trim(c)) + 1
Next c
End With
End Sub
'*****************************************************************************
Option Explicit
Sub concColour()
Dim i As Long, j As Long, s As Long, l As Long, clr As Long, vals As Variant
With Worksheets("sheet4")
For i = 1 To .Cells(.Rows.Count, "A").End(xlUp).Row
vals = Application.Transpose(Application.Transpose(Intersect(.Range("A:D"), .Rows(i)).Value2))
.Cells(i, "E") = Join(vals, vbLf)
s = 1
For j = LBound(vals) To UBound(vals)
l = Len(vals(j))
clr = .Cells(i, "A").Offset(0, j - 1).Font.Color
With .Cells(i, "E").Characters(Start:=s, Length:=l).Font
.Color = clr
End With
s = s + l + 1
Next j
.Cells(i, "E").Font.Size = 4
Next i
End With
End Sub
enter image description here
I think you require something like this. Change source font and formats as per your requirement.
Sub Adding_T()
Dim lena As Integer
Dim lenc As Integer
Dim lend As Integer
Dim lene As Integer
Dim LastRow As Long
Dim nrow As Long
With Worksheets("Sheet2") 'Change sheet as per your requirement
LastRow = .Cells(.Rows.Count, "A").End(xlUp).row
For nrow = 1 To LastRow
.Range("E" & nrow) = .Range("A" & nrow).Value2 & Chr(13) & Chr(10) & .Range("B" & nrow).Value2 & _
Chr(13) & Chr(10) & .Range("C" & nrow).Value2 & Chr(13) & Chr(10) & .Range("D" & nrow).Value2
lena = Len(.Range("A" & nrow).Value2)
lenc = lena + 2 + Len(.Range("B" & nrow).Value2)
lend = lenc + 2 + Len(.Range("C" & nrow).Value2)
lene = lend + 2 + Len(.Range("D" & nrow).Value2)
For i = 1 To lena
.Range("E" & nrow).Characters(Start:=i, Length:=1).Font.Color = _
.Range("A" & nrow).Characters(Start:=i, Length:=1).Font.Color
Next i
For i = lena + 2 To lenc
.Range("E" & nrow).Characters(Start:=i, Length:=1).Font.Color = _
.Range("B" & nrow).Characters(Start:=i, Length:=1).Font.Color
Next i
For i = lenc + 2 To lend
.Range("E" & nrow).Characters(Start:=i, Length:=1).Font.Color = _
.Range("C" & nrow).Characters(Start:=i, Length:=1).Font.Color
Next i
For i = lend + 2 To lene
.Range("E" & nrow).Characters(Start:=i, Length:=1).Font.Color = _
.Range("D" & nrow).Characters(Start:=i, Length:=1).Font.Color
Next i
Next
End With
End Sub
Snapshot of trial:
EDIT: OP Preferred code does not permit looping through the Range. Amended his Sub Test() to allow looping through the range.
Sub Test2()
Dim ws As Worksheet
Dim LastRow As Long
Set ws = ThisWorkbook.ActiveSheet
Dim rng As Range
Dim row As Range
Dim rw As Long
LastRow = ws.Cells(Rows.Count, "A").End(xlUp).row
rw = 1
For rw = 1 To LastRow
Set rng = ws.Range("A" & rw & ":C" & rw)
Call concatenate_cells_formats(Cells(rw, 4), rng)
Next
End Sub
Results are as per snapshot appended here.
This is a follow on from How do I get all the different unique combinations of 3 columns using VBA in Excel?
It almost what i need, however, my requirements is that it sums the third column which will contain figures instead of yes/no
Sub sample()
Dim ws As Worksheet
Dim lRow As Long, i As Long, j As Long
Dim col As New Collection
Dim Itm
Dim cField As String
Const deLim As String = "#"
Set ws = ThisWorkbook.Sheets("Sheet1")
With ws
lRow = .Range("A" & .Rows.Count).End(xlUp).Row
For i = 2 To lRow
cField = .Range("A" & i).Value & deLim & _
.Range("B" & i).Value & deLim & _
.Range("C" & i).Value
On Error Resume Next
col.Add cField, CStr(cField)
On Error GoTo 0
Next i
i = 2
.Range("A1:C1").Copy .Range("F1")
.Range("I1").Value = "Count"
For Each Itm In col
.Range("F" & i).Value = Split(Itm, deLim)(0)
.Range("G" & i).Value = Split(Itm, deLim)(1)
.Range("H" & i).Value = Split(Itm, deLim)(2)
For j = 2 To lRow
cField = .Range("A" & j).Value & deLim & _
.Range("B" & j).Value & deLim & _
.Range("C" & j).Value
If Itm = cField Then nCount = nCount + 1
Next
.Range("I" & i).Value = nCount
i = i + 1
nCount = 0
Next Itm
End With
End Sub
This code was originally added by
Siddharth Rout
try this (follows comments)
Option Explicit
Sub Main()
Dim i As Long
Dim dict As Object
Set dict = CreateObject("Scripting.Dictionary")
For i = 4 To Range("A" & Rows.Count).End(xlUp).Row '<-- change 4 and "A" to your data actual upleftmost cell row and column
dict(cells(i, 1).Value & "|" & cells(i, 2).Value) = dict(cells(i, 1).Value & "|" & cells(i, 2).Value) + cells(i, 3).Value '<--| change 3 to your actual "column to sum up" index
Next
With Range("G3").Resize(dict.Count) '<-- change "G3" to your actual upleftmost cell to start writing output data from
.Value = Application.Transpose(dict.Keys)
.TextToColumns Destination:=.cells, DataType:=xlDelimited, Other:=True, OtherChar:="|"
.Offset(, 2).Resize(dict.Count).Value = Application.Transpose(dict.Items) '<--| change 2 to your actual column offset where to start writing summed values form
End With
End Sub
I am using the following code - thanks #bonCodigo
Sub groupConcat()
Dim dc As Object
Dim inputArray As Variant
Dim i As Integer
Set dc = CreateObject("Scripting.Dictionary")
inputArray = WorksheetFunction.Transpose(Sheets(1).Range("A2:B7").Value)
'-- assuming you only have two columns - otherwise you need two loops
For i = LBound(inputArray, 2) To UBound(inputArray, 2)
If Not dc.Exists(inputArray(1, i)) Then
dc.Add inputArray(1, i), inputArray(2, i)
Else
dc.Item(inputArray(1, i)) = dc.Item(inputArray(1, i)) _
& "; " & inputArray(2, i)
End If
Next i
'--output into sheet
Sheets(1).Range("D2").Resize(UBound(dc.keys) + 1) = _
Application.Transpose(dc.keys)
Sheets(1).Range("E2").Resize(UBound(dc.items) + 1) = _
Application.Transpose(dc.items)
Set dc = Nothing
End Sub
A very elegant solution. Unfortunately, I am running into the limitation of using Transpose method. I have long strings that I would like to concatenate using the above code.
Any help will be appreciated.
Regards
This also uses a variant array but without the `Transpose`. It will ignore blank values to boot.
It runs by column, then by row
Sub Bagshaw()
Dim allPosts As Variant
Dim allPosts2 As Variant
Dim lngRow As Long
Dim lngCol As Long
Dim lngCnt As Long
Dim objDic As Object
Set objDic = CreateObject("Scripting.Dictionary")
allPosts = Range("A2:B5000").Value2
ReDim allPosts2(1 To UBound(allPosts, 1) * UBound(allPosts, 2), 1 To 1)
For lngCol = 1 To UBound(allPosts, 2)
For lngRow = 1 To UBound(allPosts, 1)
If Not objDic.exists(allPosts(lngRow, lngCol)) Then
If Len(allPosts(lngRow, lngCol)) > 0 Then
objDic.Add allPosts(lngRow, lngCol), 1
lngCnt = lngCnt + 1
allPosts2(lngCnt, 1) = allPosts(lngRow, lngCol)
End If
End If
Next
Next
Range("D2").Resize(UBound(allPosts2, 1)).Value2 = allPosts2
End Sub
Sub groupConcat()
Dim r As Range
Dim ro As Range
Dim myr As Range
Dim vcompt As Integer
vcompt = 0
Set ro = Range(Range("A2"), Range("A2").End(xlDown))
For i = Range("A2").Row To Range("A2").End(xlDown).Row
Debug.Print Range("A" & i).Address
Set myr = ro.Find(what:=Range("A" & i).Value, after:=Range("A2").End(xlDown), Lookat:=xlWhole, SearchDirection:=xlNext)
If myr Is Nothing Or myr.Address = Range("A" & i).Address Then
mystr = Range("A" & i).Offset(0, 1).Value
Set r = Range(Range("A" & i), Range("A2").End(xlDown))
Set myr = r.Find(what:=Range("A" & i).Value, Lookat:=xlWhole, SearchDirection:=xlNext)
If Not myr Is Nothing And r.Address <> Range("A2").End(xlDown).Address Then
Do While myr.Address <> Range("A" & i).Address
Debug.Print "r: " & r.Address
Debug.Print "myr: " & myr.Address
mystr = mystr & "; " & myr.Offset(0, 1).Value
Set myr = r.FindNext(myr)
Loop
End If
Range("D" & 2 + vcompt).Value = Range("A" & i).Value
Range("D" & 2 + vcompt).Offset(0, 1).Value = mystr
vcompt = vcompt + 1
End If
Next i
End Sub