VBA ActiveSheet.Cells behaving unexpectedly - excel

I'm working on a VBA word script that reads in some names and relevant info from an excel sheet, performs some computations to organize them correctly, and then pastes them into the word doc. This went well until I decided to make a function that would move a cell with the value "Anonymous" to the top of a range. For some reason, this isn't happening, and it appears to be because the .Cells method isn't always referring to the cell it was called on.
As the script itself is fairly long, I won't post the entire thing here. However, the relevant parts are a For loop in the main sub which deals with cells with the value "Anonymous"
For curCol = 7 To 15
lastRow = appXL.Cells(appXL.Rows.Count, curCol).End(xlUp).Row
For curRow = 1 To lastRow
Dim curCell As excel.Range
Set curCell = appXL.Cells(curRow, curCol)
Dim anonCount As Integer
anonCount = 0
If curCell.Value = "Anonymous" Or curCell.Value = "Anonymous*" Then
If anonCount < 1 Then
anonCount = anonCount + 1
MoveAnon (curRow), (curCol), (lastRow)
Else
anonCount = anonCount + 1
curCell.Value = curCell.Value + " (" + CStr(anonCount) + ")"
MoveAnon (curRow), (curCol), (lastRow)
End If
End If
Next curRow
Next curCol
You'll notice that within this loop is a call to a subroutine "MoveAnon" which is
Sub MoveAnon(currentRow As Integer, currentCol As Integer, thelastRow As Integer)
Dim text As String
Debug.Print ("Using Row: " + CStr(currentRow) + ", Column: " + CStr(currentCol) + ", Last Row: " + CStr(thelastRow))
text = excel.Application.ActiveSheet.Cells(currentRow, currentCol)
Debug.Print ("Hit On: " & excel.Application.ActiveSheet.Cells(currentRow, currentCol))
If currentRow > 1 Then
excel.Application.ActiveSheet.Range(excel.Application.ActiveSheet.Cells(1, currentCol).Address, excel.Application.ActiveSheet.Cells(currentRow - 1, currentCol).Address).Cut excel.Application.ActiveSheet.Range(excel.Application.ActiveSheet.Cells(2, currentCol).Address)
excel.Application.ActiveSheet.Cells(1, currentCol).Value = text
End If
End Sub
Through testing and with Deubg.Print, I've noticed that the line Debug.Print ("Hit On: " & excel.Application.ActiveSheet.Cells(currentRow, currentCol)) refers to all manner of different cells then the one on which it was called. For example, whenever I use Cells(6, 15), I get a value from a cell that is actually on row 42, column 15. The difference between the cell its called on and the cell it returns is not always the same (I've seen -7, +36, and 0), but it is always in the correct column.
Does anyone have any idea as to what my cause this behavior to arise? Thanks for any help.

It's much faster to read the whole range into an array, then populate another array of the same size with the "Anonymous*" at the top, and replace the range values using the second array.
Eg.
Sub Tester()
Dim curCol As Long, ws As Worksheet
Set ws = ActiveSheet
For curCol = 7 To 15
MoveAnon ws.Range(ws.Cells(1, curCol), _
ws.Cells(ws.Rows.Count, curCol).End(xlUp))
Next curCol
End Sub
'Given a (single-column) range, move all values like "Anonymous*"
' to the top of the range
Sub MoveAnon(rng As Range)
Const TXT As String = "Anonymous*"
Dim v, i As Long, num As Long
Dim arrIn, arrOut, nA As Long, nX As Long
num = Application.CountIf(rng, TXT) 'how many to float up
If num = 0 Then Exit Sub 'nothing to do here?
arrIn = rng.Value 'read to array
ReDim arrOut(1 To UBound(arrIn, 1), 1 To UBound(arrIn, 2)) 'size output array
For i = 1 To UBound(arrIn, 1) 'loop the input array
v = arrIn(i, 1)
If v Like TXT Then
nA = nA + 1
arrOut(nA, 1) = v '"Anonymous*" goes at the top
Else
nX = nX + 1
arrOut(num + nX, 1) = v 'everything else goes below
End If
Next i
rng.Value = arrOut 'replace using the shuffled array
End Sub

Related

How can i use VBA Code to Copy and Paste Specific Cells if Condition is Met in two or more worksheets to different areas of another worksheet

Looking for a little more help please. I was here a month ago a RiskyPenguin gave me a great bit of code. I would like to add to this.
This is the part that works:
So if the "invoice" spreadsheet (sheet 5), if cell G4 (for example is I111) matches any of the data in the first column of the "income" spreadsheet (sheet 1) (starting at row 6) then the corresponding data in columns 2 3, 8 & 9 will copy over to the "invoice" spreadsheet in columns 2, 3, 4 & 5 (starting at row 13).
Sub FindAndCopyData2()
Dim shData As Worksheet, shReport As Worksheet
Set shData = Sheet1
Set shReport = Sheet6
Dim strInvoceNumber As String
strInvoceNumber = shReport.Cells(4, "E").Value
Dim intLastRow As Integer
intLastRow = shData.Cells(Rows.Count, 1).End(xlUp).Row
Dim intReportRow As Integer
intReportRow = 13
shReport.Range("B13:E20").ClearContents
Dim i As Integer
For i = 1 To intLastRow
If shData.Cells(i, 1).Value2 = strInvoceNumber Then
shReport.Cells(intReportRow, 2).Value2 = shData.Cells(i, 3).Value2
shReport.Cells(intReportRow, 3).Value2 = shData.Cells(i, 4).Value2
shReport.Cells(intReportRow, 4).Value2 = shData.Cells(i, 8).Value2
shReport.Cells(intReportRow, 5).Value2 = shData.Cells(i, 9).Value2
intReportRow = intReportRow + 1
End If
Next i
End Sub
I would then like to (hopefully using the same search)
Take the "invoice" spreadsheet (sheet 5), if cell G4 (for example is I111) matches any of the data in the second column of the "expenses" spreadsheet (sheet 2) (starting at row 11) then the corresponding data in columns 3, 5, & 7 will copy over to the "invoice" spreadsheet in columns 2, 4 & 6 (starting at row 13).
Is this possible or does it have to be a separate piece of programming?
Many Thanks for any advise.
Assuming this could be useful for others I made a function out of it and refactored the initial code to handle the copy in memory. I setup your first lookup so you just need to edit the variables to get your second lookup:
Option Explicit
''''''''''''''''''''''''''''''''''''''
''Main Sub
''''''''''''''''''''''''''''''''''''''''''''''''''
Sub main()
'Set some vars
Dim sourceArr, targetArr, sourceCls, targetCls, sourceStartRw As Long, targetStartRw As Long, dict As Object, j As Long, sourceLookupCl As Long, Matchkey As Long
''''''''''''''''''''''''''''''''''''''
''Lookup 1
''''''''''''''''''''''''''''''''''''''''''''''''''
Matchkey = Sheet5.Range("G4").Value2 'lookupKey
sourceCls = Split("2,3,8,9 ", ",") 'Columns to copy from
targetCls = Split("2,3,4,5", ",") 'Columns to copy to
sourceStartRw = 6
targetStartRw = 13
sourceLookupCl = 1 'matching column
'get data in memory = array
sourceArr = Sheet1.Range("A1").CurrentRegion.Value2
'call our function
targetArr = reorder(sourceArr, sourceCls, targetCls, sourceStartRw, sourceLookupCl, Matchkey)
'dump to sheet
With Sheet5
.Range(.Cells(targetStartRw, 1), .Cells(UBound(targetArr) + targetStartRw - 1, UBound(targetArr, 2))).Value2 = targetArr
End With
''''''''''''''''''''''''''''''''''''''
''Lookup 2 => change source and target cols to your need
''''''''''''''''''''''''''''''''''''''''''''''''''
Matchkey = Sheet5.Range("G4").Value2
sourceCls = Split("2,3,8,9 ", ",")
targetCls = Split("2,3,4,5", ",")
sourceStartRw = 6
targetStartRw = 13 'must be the same as previous lookup if you want to keep the targetArr from previous lookups
sourceLookupCl = 1
'get data in memory = array
sourceArr = Sheet1.Range("A1").CurrentRegion.Value2
'call our function keeping the data from the first lookup
targetArr = reorder(sourceArr, sourceCls, targetCls, sourceStartRw, sourceLookupCl, Matchkey, targetArr)
'dump to sheet
With Sheet5
.Range(.Cells(targetStartRw, 1), .Cells(UBound(targetArr) + targetStartRw - 1, UBound(targetArr, 2))).Value2 = targetArr
End With
End Sub
''''''''''''''''''''''''''''''''''''''
''Supporting function
''''''''''''''''''''''''''''''''''''''''''''''''''
Private Function reorder(sourceArr, sourceCls, targetCls, sourceStartRw As Long, sourceLookupCl As Long, Matchkey As Long, Optional targetArr) As Variant
Dim dict As Object, j As Long
'if the target array overlaps the previous lookups pass it to the function
If IsMissing(targetArr) Then
ReDim targetArr(1 To UBound(sourceArr), 1 To UBound(sourceArr, 2))
End If
'build a dict to compare quickly
Set dict = CreateObject("Scripting.Dictionary") 'create dictionary lateB
For j = 1 To UBound(sourceArr) 'traverse source
dict(sourceArr(j, sourceLookupCl)) = Empty
Next j
'check if key exists in dict and copy data
Dim i As Long, ii As Long ': ii = 1
If dict.Exists(Matchkey) Then
For j = sourceStartRw To UBound(sourceArr)
For i = 1 To UBound(sourceArr, 2)
If i = sourceCls(ii) Then
targetArr(j - sourceStartRw + 1, targetCls(ii)) = sourceArr(j, i)
ii = IIf(ii < UBound(sourceCls), ii + 1, ii)
End If
Next i
ii = 0
Next j
End If
reorder = targetArr
End Function

Create a table with all potential combinations from a given list with two columns (excel)

Is there a way (vba code or excel trick) to manipulate a 2 columnar list so that I get a table with all potential combinations depending on a unique identifier in the first column?
E.g. I have one column with Company Names and another with Country Locations. What I need is every set if combinations of the countries per company (see screenshot attached).
This vba module should solve your problem.
Just copy the code to a new module, declare the input and output columns and the number of the first row of your list.
Note that the code will stop once it hits a line where the "Unique Identifier" Cell is empty.
Also, it requires that your list is sorted with respect to your "Unique Identifier".
If a Unique Identifier only appears once, it will still be written into the output list, but only once and with the outColNation2 staying empty in that row. If this is not desired and it should be left out entirely, just delete the commented if-statement.
Example Image of output
Also note, that a unique identifier can repeat at most 100 times. I assume none of them appears that often as that would create a ridiculously long output list.
Option Compare Text
Sub COMBINATIONS()
Dim i As Long, j As Long, k As Long, l As Long, n As Long
Dim arr(100) As String
Dim UI As String
Dim inColUI As Integer, inColNation As Integer
Dim outColUI As Integer, outColNation1 As Integer, outColNation2 As Integer
Dim FirstRowOfData As Integer
Dim YourWS As Worksheet
inColUI = 1 'Column of the "Unique Identifier"
inColNation = 2 'Column of the "Nations" in your example
outColUI = 4
outColNation1 = 5 'output columns
outColNation2 = 6
FirstRowOfData = 2 'First Row of data
Set YourWS = Application.Worksheets("Sheet1") 'Put in your Worksheet Name here.
i = FirstRowOfData
n = FirstRowOfData
With YourWS
Do Until .Cells(i, inColUI) = ""
j = 0
UI = .Cells(i, inColUI)
Do Until .Cells(i - 1, inColUI) <> .Cells(i, inColUI) And j > 0 Or .Cells(i, inColUI) = ""
arr(j + 1) = .Cells(i, inColNation)
i = i + 1
j = j + 1
Loop
If j = 1 Then '<- remove this if-statement and the following marked lines if single appearing UIs should be omitted entirely
.Cells(n, outColUI) = UI '<---
.Cells(n, outColNation1) = arr(1) '<---
n = n + 1 '<---
Else '<---
For k = 1 To j
For l = 1 To j
If arr(k) <> arr(l) Then
.Cells(n, outColUI) = UI
.Cells(n, outColNation1) = arr(k)
.Cells(n, outColNation2) = arr(l)
n = n + 1
End If
Next l
Next k
End If '<---
Loop
End With
End Sub
Edit: cleaned up the code a little bit
Something like the following shows how to iterate through 2 ranges of cells
Dim Rng1 as Range, Rng2 as Range
Dim SrcCell as Range, OthrCell as Range
Dim FullList as string
Rng1 = Range("A1:A12")
Rng2 = Range("B1:B12")
FullList = ""
For Each SrcCell in Rng1
For Each OthrCell in Rng2
FullList = IIF(FullList="","",FullList & vbCrLf) & SrcCell.Value & OthrCell.Value
Next OthrCell
Next srcCell
The FullList string now contains all the combinations but you may require something else. Only intended to give you a start
You need to add code yourself to filter out duplicates
You can do the following (see code below). As another commentee mentioned, when there is only one record of company vs country, it will not show in the output.
The solutions is based on creating a dictionary, each entry is a company and the value is a comma separated string of countries. After the dictionary is created, the dictionary is looped, and a list of countries is then iterated over a nested loop. If the index of the outer loop is the same as the inner index of the loop then the loop is skipped i.e. that would be a Country 1 vs Country 1 combination. Otherwise is added to the output list.
Columns A,B is input and columns D,E,F is output.
Option Explicit
Public Sub sCombine()
Dim r As Range, dest As Range
Dim d As New Dictionary
Dim key As Variant
Dim countries() As String
Dim i As Integer, j As Integer
On Error GoTo error_next
Set r = Sheet1.Range("A1")
Set dest = Sheet1.Range("D:F")
dest.ClearContents
Set dest = Sheet1.Range("D1")
While r.Value <> ""
If d.Exists(r.Value) Then
d(r.Value) = d(r.Value) & "," & r.Offset(0, 1)
Else
d.Add r.Value, r.Offset(0, 1).Value
End If
Set r = r.Offset(1, 0)
Wend
For Each key In d.Keys
countries = Split(d(key), ",")
For i = LBound(countries) To UBound(countries)
For j = LBound(countries) To UBound(countries)
If i <> j Then
dest.Value = key
dest.Offset(0, 1).Value = countries(i)
dest.Offset(0, 2).Value = countries(j)
Set dest = dest.Offset(1, 0)
End If
Next j
Next i
Next key
Exit Sub
error_next:
MsgBox Err.Description
End Sub

Excel VBA to loop and find specific range and concatenate 2 cell values and delete empty cell

I am trying to identify a specific range in column-A and concatenate two cells within the specific range and delete the empty cell. I have been successful in putting a code together and it does the job very well. But, I don't know how to loop it to identify next range. Any help would be appreciated.
As per below image and code, First, I am finding and selecting a range between two (MCS) in column-A with a condition that, if the rows are more than 8 between two MCS. Then I am concatenating first 2 cells immediately after MCS and delete the empty row.
The below code works well for first range but I am unable to loop to identify next range from row 22 to 32 and perform concatenations.
I dont know how to loop in column-A and select ranges and concatenate. Any help would be much appreciated. Thanks
Sub MergeStem()
Dim findMCS1 As Long
Dim findMCS2 As Long
Dim myCount As Integer
Dim myStems As Long
Dim mySelect As Range
Dim c As Range
findMCS1 = Range("A:A").Find("MCS", Range("A1")).Row
findMCS2 = Range("A:A").Find("MCS", Range("A" & findMCS1)).Row
myCount = Range("A" & findMCS1 + 1 & ":A" & findMCS2 - 1).Cells.Count
Range("B1").Value = myCount
MsgBox "Number of rows =" & myCount
Set mySelect = Selection
If myCount > 8 Then
myStems = Range("A" & findMCS1 + 2 & ":A" & findMCS2 - 9).Select
Set mySelect = Selection
For Each c In mySelect.Cells
If firstcell = "" Then firstcell = c.Address(bRow, bCol)
sArgs = sArgs + c.Text + " "
c.Value = ""
Next
Range(firstcell).Value = sArgs
End If
Columns("A").SpecialCells(xlCellTypeBlanks).EntireRow.Delete
Application.ScreenUpdating = True
End Sub
Can you try this? Ordinarily, Find would be the way to go but because you are deleting rows it's hard to keep track of which cells you've found.
Sub x()
Dim r As Long, n1 As Long, n2 As Long
With Range("A1", Range("A" & Rows.Count).End(xlUp))
For r = .Count To 1 Step -1
If .Cells(r).Value = "MCS" Then
If n1 = 0 Then
n1 = .Cells(r).Row
Else
n2 = .Cells(r).Row
End If
If n1 > 0 And n2 > 0 Then
If n1 - n2 > 9 Then
.Cells(r + 1).Value = .Cells(r + 1).Value & .Cells(r + 2).Value
'.Cells(r + 2).EntireRow.Delete
'Call procedure to delete row
End If
n1 = n2
n2 = 0
End If
End If
Next r
End With
End Sub

Calculate from an array in memory

I am fairly new to VBA but understand the basics. My question is as follows:
I need to divide the individual cells of an array with its corresponding offset cell (E3/E2, F3/F2, G3/G2, etc.) and store it in an array. Then, I need to find the 1st, 2nd, and 3rd smallest numbers of that array and highlight the cell in the first row of that column. Here is what I have:
Option Base 1
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
'Private Sub test5()
Dim row As Integer
Dim column As Integer
Dim myArray(10) As Double
Dim myArray1(3) As String
Dim a As Long
Dim b As Long
Dim intQuizNumber As Integer
Dim intTestNumber As Integer
Dim intProjectNumber As Integer
intQuizNumber = 3
intTestNumber = 3
intProjectNumber = 3
On Error Resume Next
If Not Intersect(Target, Range(Range("D3"), Range("D3").End(xlDown))) Is Nothing Then
Range("1:1").Interior.Color = xlNone
row = ActiveCell.row
column = ActiveCell.column
For a = 1 To 10
myArray(a) = Cells(row, column + 1) / Cells(2, column + 1)
column = column + 1
Next a
row = ActiveCell.row
column = ActiveCell.column
'Evaluate("=RANK(E3,$E$3:$N$3,0)+COUNTIF($E$3:E3,E3)-1")
For b = 1 To 3
myArray1(b) = Evaluate("=CELL(""address"",OFFSET(" & Target.Offset(0, 1).Address & ",0,MATCH(SMALL(" & Target.Offset(0, 1).Address & ":" & Target.Offset(0, 3 + 3 + 3 + 1).Address & "," & b & ")," & Target.Offset(0, 1).Address & ":" & Target.Offset(0, 3 + 3 + 3 + 1).Address & ",0)-1))")
Next b
Union(Range(myArray1(1)).Offset(-row + 1, 0), Range(myArray1(2)).Offset(-row + 1, 0), Range(myArray1(3)).Offset(-row + 1, 0)).Interior.Color = 65535
Else
Range("1:1").Interior.Color = xlNone
End If
End Sub
I would like to replace the Evaluate statement in "b" loop with the one that I have commented out but can't seem to do it. I first need the value of the division and then I need to get the three lowest and highlight the cells. I've searched on Google thoroughly and can't figure this out. Any help would be greatly appreciated!!
Thank You
I'm not sure why you want to use RANK instead of what you have, but here's another way to get what you want.
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
Dim i As Long
Dim vaNums As Variant, vaDenoms As Variant, aDivs() As Double
Dim wf As WorksheetFunction
Dim lSmall As Long
Dim rRow As Range
Dim rStart As Range
Const lCOLS As Long = 10
Const lMARKCNT As Long = 3
If Not Intersect(Target.Cells(1), Me.Range("D3", Me.Range("D3").End(xlDown))) Is Nothing Then
Set wf = Application.WorksheetFunction ' this just makes our code easier to read
'If these ever change, you only have to change them in one place
Set rRow = Target.Cells(1).Offset(0, 1).Resize(1, lCOLS)
Set rStart = Me.Cells(1, 5)
'Clear existing colors
rStart.Resize(1, lCOLS).Interior.ColorIndex = xlNone
'Read the current line and the 2nd line into arrays
'This shortcut creates two-dimensional arrays
vaNums = rRow.Value
vaDenoms = rStart.Offset(1, 0).Resize(1, lCOLS).Value
'Do the division and store it in aDivs()
ReDim aDivs(LBound(vaNums, 2) To UBound(vaNums, 2))
For i = LBound(vaNums, 2) To UBound(vaNums, 2)
aDivs(i) = vaNums(1, i) / vaDenoms(1, i) + (i / 10000)
Next i
'Find the nth smallest value and gets its position with MATCH
'Then use that position to color the cell
For i = 1 To 3
lSmall = wf.Match(wf.Small(aDivs, i), aDivs, False)
rStart.Offset(0, lSmall - 1).Interior.Color = vbYellow
Next i
End If
End Sub

Divide a string in a single cell into several cells

I have data that I need to split into individual points. My macro charts the data, as a scatter plot, with: Column A as the title of the chart, Column B as the X axis, and Columns C and D as the Y axis. What I need is for when the Product ID has more than 1 number listed to split the numbers out into their own rows and keep the columns B, C, and D the same for each row created form the original. So for row 167, I would want 3 rows (001,002,003) each with packaging, 200, and 100, in B, C, and D respectively. I am not sure where to begin. I tried to build a macro but, I immediately got tripped up when I tried to record a "Find" Formula to run on the data. Any help would be greatly appreciated.
Column A: 001, 002, 003 // Column B:packaging // Column C:200 // Column D:100
Sorry I couldn't post a screenshot of my data, the forum won't let me. If you have any questions please let me know, I will be sure to check in frequently.
Thanks in advance.
I worte this VERY quickly and without much care for efficiency, but this should do the trick:
Sub SplitUpVals()
Dim i As Long
Dim ValsToCopy As Range
Dim MaxRows As Long
Dim ValToSplit() As String
Dim CurrentVal As Variant
MaxRows = Range("A1").End(xlDown).Row
For i = 1 To 10000000
ValToSplit = Split(Cells(i, 1).Value, ",")
Set ValsToCopy = Range("B" & i & ":D" & i)
For Each CurrentVal In ValToSplit
CurrentVal = Trim(CurrentVal)
Cells(i, 1).Value = CurrentVal
Range("B" & i & ":D" & i).Value = ValsToCopy.Value
Cells(i + 1, 1).EntireRow.Insert
i = i + 1
MaxRows = MaxRows + 1
Next
Cells(i, 1).EntireRow.Delete
If i > MaxRows Then Exit For
Next i
End Sub
As a note, make sure there's no data in cells beneath your data as it might get deleted.
You will need to parse the data in column A. I would do this by splitting the string in to an array, and then iterate over the array items to add/insert additional rows where necessary.
Without seeing your worksheet, I would probably start with something like this, which will split your cell value from column A in to an array, and then you can iterate over the items in the array to manipulate the worksheet as needed.
Sub TestSplit()
Dim myString as String
Dim myArray() as String
Dim cell as Range
Dim i as Long
For each cell in Range("A2",Range("A2").End(xlDown))
myString = cell.Value
myArray = Split(myString, ",") '<-- converts the comma-delimited string in to an array
For i = lBound(myArray) to uBound(myArray)
If i >= 1 Then
'Add code to manipulate your worksheet, here
End If
Next
Next
End Sub
This is a better solution (now that I had more time :) ) - Hope this does the trick!
Sub SplitUpVals()
Dim AllVals As Variant
Dim ArrayIndex As Integer
Dim RowLooper As Integer
AllVals = Range("A1").CurrentRegion
Range("A1").CurrentRegion.Clear
RowLooper = 1
For ArrayIndex = 1 To UBound(AllVals, 1)
ValToSplit = Split(AllVals(ArrayIndex, 1), ",")
For Each CurrentVal In ValToSplit
CurrentVal = Trim(CurrentVal)
Cells(RowLooper, 1).Value = CurrentVal
Cells(RowLooper, 2).Value = AllVals(ArrayIndex, 2)
Cells(RowLooper, 3).Value = AllVals(ArrayIndex, 3)
Cells(RowLooper, 4).Value = AllVals(ArrayIndex, 4)
RowLooper = RowLooper + 1
Next
Next ArrayIndex
End Sub
Sub DivideData()
'This splits any codes combined into the same line, into their own separate lines with their own separate data
Dim a, b, txt As String, e, s, x As Long, n As Long, i As Long, ii As Long
With Range("a1").CurrentRegion
a = .Value
txt = Join$(Application.Transpose(.Columns(1).Value))
x = Len(txt) - Len(Replace(txt, ",", "")) + .Rows.Count
ReDim b(1 To x * 2, 1 To UBound(a, 2))
For i = 1 To UBound(a, 1)
For Each e In Split(a(i, 1), ",")
If e <> "" Then
For Each s In Split(e, "-")
n = n + 1
For ii = 1 To UBound(a, 2)
b(n, ii) = a(i, ii)
Next
b(n, 1) = s
Next
End If
Next
Next
With .Resize(n)
.Columns(1).NumberFormat = "#"
.Value = b
End With
End With
End Sub

Resources