DateAdd proper date variable recognition - vba

So I've gone over this code for the best part of 4 hours fiddling with it, rewriting from scratch. The only thing I got out of this was the reduction in the code from about 15 lines to the now 9.
Anyways, the problem with the code is that it is not properly recognizing the arrDateTime date with the intArrayIndex-1. Instead of the normal date say "June 7, 2013", which I can retrieve inside the k=0 if statement, it comes back with "December 30, 1899" which I read occurs when the date statement is incorrect.
Also, I've tried using specific numbers just to test them out and it has no problem in the j=0 portion, however, for some reason the j=1 statement didn't work. I've also tried simplyfying the code by having the 1-j instead of the 1 in the DateAdd variable, however it doesn't want to add no days.
'grabs date and time
If (k = 0) Then
intDay = Cells(intRowNum + 2, 2).Value
arrDateTime(intArrayIndex) = DateValue(strMonth & " " & intDay & ", " & intYear) + (Cells(intRowNum + intMaxRows + 3, 1).Value)
ElseIf j = 0 Then
arrDateTime(intArrayIndex) = DateAdd("d", 1, arrDateTime(intArrayIndex - 1))
ElseIf j = 1 Then
arrDateTime(intArrayIndex) = arrDateTime(intArrayIndex - 1)
End If
I'm getting desperate here, any help whatsoever in figuring out why the date variable is incorrectly used would be greatly appreciated.
Update 1
As requested I have included absolutely every piece of code relative to the problem, I didn't include everything as it's 400+ lines long.
Dim intRowNum As Integer
Dim intMaxRows As Integer
Dim intArrayIndex As Integer
Dim intYear As Integer
Dim intDay As Integer
Dim strMonth As String
Dim arrTitle(0 To 9) As String
Dim arrDescription(0 To 9) As String
Dim arrProf(0 To 9) As String
Dim arrDateTime(9) As Date
For j = 0 To 1
For k = 0 To 4
intArrayIndex = k * 2 + j
'grabs date and time
If (k = 0) Then
intDay = Cells(intRowNum + 2, 2).Value
arrDateTime(intArrayIndex) = DateValue(strMonth & " " & intDay & ", " & intYear) + (Cells(intRowNum + intMaxRows + 3, 1).Value)
ElseIf j = 0 Then
arrDateTime(intArrayIndex) = DateAdd("d", 1, arrDateTime(intArrayIndex - 1))
ElseIf j = 1 Then
arrDateTime(intArrayIndex) = arrDateTime(intArrayIndex - 1)
End If
Next
Next
For j = 0 To 9
ActiveSheet.Cells(3 + j, 1).Value = j + 1
ActiveSheet.Cells(3 + j, 5).Value = TimeValue(arrDateTime(j))
ActiveSheet.Cells(3 + j, 6).Value = MonthName(month(arrDateTime(j)))
ActiveSheet.Cells(3 + j, 7).Value = Day(arrDateTime(j))
ActiveSheet.Cells(3 + j, 8).Value = Year(arrDateTime(j))
Next

Your iteration goes as follows:
Turn j k intArrayIndex arrDateTime(intArrayIndex)
1 0 0 0 is created your date on first array position
2 0 1 2 arrDateTime(2 -1) does not exist, it is empty/zero!!
therefore trying to add 1 day to zero result with what you have.

Related

My current code finds the vertex cover for five nodes. How would I generalize it to any number of nodes? Should I try recursion?

I am writing a code for a project that is trying to find the minimum solution to the Vertex Cover Problem: Given a graph, find the minimum number of vertices needed to cover the graph.
I am trying to write a program for a brute force search through the entire solution space. Right now, my code works by doing the following:
Example using 4 nodes:
Check Every Single Node: Solution Space: {1}, {2}, {3}, {4}
Check Every Couple of Nodes: Solution Space: {1,2}, {1,3}, {1,4}, {2,3}, {2,4}, {3,4}
Check Every Triple of Nodes: Solution Space: {1,2,3}, {1,2,4}, {2,3,4}
Check Every Quadruple of Nodes: Solution Space: {1,2,3,4}
Currently, my code works for 5 nodes. The problem is that it searches through these permutations using a fixed number of nested while loops. If I wanted to run 6 nodes, I would need to add in another While loop. I am trying to generalize the code so that the number of nodes can itself be a variable.
The code finds a solution by triggering a row of binary numbers based on the solution space above, eg if the solution being tried is {1,2,4} then the first, second, and fourth binary value will be set to equal 1 while the third is set to 0. A matrix is set up to use these inputs to determine if they cover the graph. Here is a picture further showing how this works.
Any ideas on how to generalize this to any number of nodes? Thoughts on recursion?
Also, note in the code there is a section that waits for 1 second. This is just for aesthetics, it is not serving any purpose besides making the code fun to watch.
i = 0
j = 0
k = 0
m = 0
Range("Z22").Select
While i < 5 'Checks to see if a single vertice can cover the graph.
Cells(5, 20 + i).Value = 1
Application.Wait (Now + TimeValue("0:00:1"))
If Cells(21, 13).Value = Cells(22, 26).Value Then
GoTo Line1
Else
Cells(5, 20 + i) = 0
i = i + 1
End If
Wend
i = 0
While i < 4 'Checks to see if two vertices can cover the graph
Cells(5, 20 + i).Value = 1
j = i + 1
While j < 5
Cells(5, 20 + j).Value = 1
Application.Wait (Now + TimeValue("0:00:1"))
If Cells(21, 13).Value = Cells(22, 26).Value Then
GoTo Line1
Else
Cells(5, 20 + j) = 0
j = j + 1
End If
Wend
Cells(5, 20 + i) = 0
i = i + 1
Wend
k = 0
While k < 3 'Checks to see if three vertices can cover the graph
Cells(5, 20 + k) = 1
i = k + 1
While i < 4
Cells(5, 20 + i).Value = 1
j = i + 1
While j < 5
Cells(5, 20 + j).Value = 1
Application.Wait (Now + TimeValue("0:00:1"))
If Cells(21, 13).Value = Cells(22, 26).Value Then
GoTo Line1
Else
Cells(5, 20 + j) = 0
j = j + 1
End If
Wend
Cells(5, 20 + i) = 0
i = i + 1
Wend
Cells(5, 20 + k).Value = 0
k = k + 1
Wend
While m < 2 'Checks to see if four vertices can cover the graph
Cells(5, 20 + m).Value = 1
k = m + 1
While k < 3
Cells(5, 20 + k) = 1
i = k + 1
While i < 4
Cells(5, 20 + i).Value = 1
j = i + 1
While j < 5
Cells(5, 20 + j).Value = 1
Application.Wait (Now + TimeValue("0:00:1"))
If Cells(21, 13).Value = Cells(22, 26).Value Then
GoTo Line1
Else
Cells(5, 20 + j) = 0
j = j + 1
End If
Wend
Cells(5, 20 + i) = 0
i = i + 1
Wend
Cells(5, 20 + k).Value = 0
k = k + 1
Wend
Cells(5, 20 + m).Value = 0
m = m + 1
Wend
If Cells(21, 13).Value <> Cells(22, 26).Value Then 'Final effort
Range("T5:X5") = 1
MsgBox ("It takes all five vertices.")
End If
Line1:
Application.DisplayAlerts = True
End Sub
This makes combinations for any n; does not use recursion. I've got to think if recursion would be applicable (make it simpler?)
Option Explicit
Const nnodes = 6
Dim a&(), icol&
Sub Main()
ThisWorkbook.Sheets("sheet1").Activate
Cells.Delete
Dim i&, j&
For i = 1 To nnodes ' from 1 to nnodes
ReDim a(i)
For j = 1 To i ' -- start with 1 up
a(j) = j
Next j
Cells(i, 1) = i ' show
icol = 2 ' for show
Do ' -- show combination and get next combination
Loop While doi(i)
Next i
End Sub
Function doi(i) As Boolean ' show and get next
Dim j&, s$
For j = 1 To i ' build string for show
If j > 1 Then s = s & ","
s = s & Str$(a(j))
Next j
Cells(i, icol) = "{" & s & "}" ' show
icol = icol + 1
' -- get next combination (if)
For j = i To 1 Step -1 ' check if any more
If a(j) < nnodes - i + j Then Exit For
Next j
If j < 1 Then doi = False: Exit Function ' no more
a(j) = a(j) + 1 ' build next combination
While j < i
a(j + 1) = a(j) + 1
j = j + 1
Wend
doi = True
End Function
EDIT: Changed "permutation" to "combination".
EDIT2: I kept coming back to recursion -- it does simplify the code:
Option Explicit
Dim icol& ' for showing combinations
Sub Main() ' get (non-empty) partitions of nnodes
Const nnodes = 6
Dim k&
ThisWorkbook.Sheets("sheet2").Activate
Cells.Delete
For k = 1 To nnodes ' k = 1 to n
Cells(k, 1) = k ' for showing
icol = 2
Call Comb("", 0, 1, nnodes, k) ' combinations(n,k)
Next k
End Sub
Sub Comb(s$, lens&, i&, n&, k&) ' build combination
Dim s2$, lens2&, j&
For j = i To n + lens + 1 - k '
If lens = 0 Then s2 = s Else s2 = s & ", "
s2 = s2 & j
lens2 = lens + 1
If lens2 = k Then ' got it?
Cells(k, icol) = "{" & s2 & "}" ' show combination
icol = icol + 1
Else
Call Comb(s2, lens2, j + 1, n, k) ' recurse
End If
Next j
End Sub

Damerau-Levenshtein algorithm isn't working on short strings

I have a for loop that takes a user's input and one of the keys in my dictionary and passes them to a Damerau-Levenshtein function and based on the distance, overwrites the user's input with the dictionary key (The for loop is to cycle through each dictionary key). This works fine enough for strings larger than three characters, but if the string is three or fewer characters the algorithm returns with the wrong key. Here's the for loop:
1950 For j = 0 To dict.Count - 1
1960 distance = DamerauLevenshtein(SplitStr(i), dict.Keys(j))
1970 'MsgBox dict.Keys(j) & vbCrLf & distance ' used for debugging
1980 If distance < 4 Then
1990 If distance < leastDist Then
2000 leastDist = distance
2010 SplitStr(i) = dict.Keys(j)
2020 End If
2030 End If
2040 Next
2050 MsgBox "The distance is: " & leastDist & vbCrLf & "The entered text was " & tempStr & vbCrLf & "The replaced word is " & SplitStr(i)
SplitStr(i) holds the user's input, which comes from a split function. I arbitrarily picked 4 for a good distance
I stole the algorithm from a bytes.com forum post. Algorithm below:
Function DamerauLevenshtein(str1, str2, Optional intSize = 256)
Dim intTotalLen, arrDistance, intLen1, intLen2, i, j, arrStr1, arrStr2, arrDA, intMini
Dim intDB, intI1, intJ1, intD
str1 = UCase(str1)
str2 = UCase(str2)
intLen1 = Len(str1)
intLen2 = Len(str2)
intTotalLen = intLen1 + intLen2
ReDim arrStr1(intLen1)
ReDim arrStr2(intLen2)
ReDim arrDA(intSize)
ReDim arrDistance(intLen1 + 2, intLen2 + 2)
arrDistance(0, 0) = intTotalLen
For i = 0 To intSize - 1
arrDA(i) = 0
Next
For i = 0 To intLen1
arrDistance(i + 1, 1) = i
arrDistance(i + 1, 0) = intTotalLen
Next
For i = 1 To intLen1
arrStr1(i - 1) = Asc(Mid(str1, i, 1))
Next
For j = 0 To intLen2
arrDistance(1, j + 1) = j
arrDistance(0, j + 1) = intTotalLen
Next
For j = 1 To intLen2
arrStr2(j - 1) = Asc(Mid(str2, j, 1))
Next
For i = 1 To intLen1
intDB = 0
For j = 1 To intLen2
intI1 = arrDA(arrStr2(j - 1))
intJ1 = intDB
If arrStr1(i - 1) = arrStr2(j - 1) Then
intD = 0
Else
intD = 1
End If
If intD = 0 Then intDB = j
intMini = arrDistance(i, j) + intD
If intMini > arrDistance(i + 1, j) + 1 Then intMini = arrDistance(i + 1, j) + 1
If intMini > arrDistance(i, j + 1) + 1 Then intMini = arrDistance(i, j + 1) + 1
If intMini > arrDistance(intI1, intJ1) + i - intI1 + j - intJ1 - 1 Then intMini = arrDistance(intI1, intJ1) + i - intI1 + j - intJ1 - 1
arrDistance(i + 1, j + 1) = intMini
Next
arrDA(arrStr1(i - 1)) = i
Next
DamerauLevenshtein = arrDistance(intLen1 + 1, intLen2 + 1)
End Function
If I type in "Cire" the algorithm correctly returns "CORE".
"Raman" returns "REMAN"
"Cosnigned" returns "CONSIGNED
However, "Now" should return "New" but returns "OCM".
"New" also returns "OCM" (so distance should be 0, but is 2.)
"FP" should be "FP" but returns "OCM", distance is 2
"DPF" Should be "DPF" but returns "OCM", distance is 2
I just learned about the algorithm, so I'm sure I'm missing something important, but I just can't see it. Thoughts?
I figured it out. After much searching I found a post saying that an edit distance is commonly 2. (They didn't specify any merits on why 2 is common)
I switched my if statement to 2 from 4 and now all of the problem terms are being corrected as they should be.

Increment number at end of string

My string is in the format Cells(i, 6) & ("-000") & (q). Here Cells(i,6).value is an integer.
I want to add 1 to q, from the string it is in.
ElseIf k > 0 Then
Sht1.Cells(erow, 3) = CInt(sht3.Cells(i, 5).value) + 1
Sht1.Cells(erow, 4) = CInt(sht3.Cells(i, 6).value) + 1
Sht1.Cells(erow, 1) = Sht1.Cells(erow - 1, 1).value + 1
End If
Try to replace your code with this:
If k > 0 Then
Sht1.Cells(erow, 3) = CInt(sht3.Cells(i, 5).value) + 1
Debug.Print CInt(sht3.Cells(i, 5).value)
Sht1.Cells(erow, 4) = CInt(sht3.Cells(i, 6).value) + 1
Debug.Print CInt(sht3.Cells(i, 6).value)
Sht1.Cells(erow, 1) = Sht1.Cells(erow - 1, 1).value + 1
Debug.Print Sht1.Cells(erow - 1, 1).value
End If
And see where it breaks. Take a look at the immediate window. Probably the value is not a number.
If you edit the code a bit, you may get what you want:
Public Sub TestMe
If k > 0 Then
Sht1.Cells(erow, 3) = IncreaseWithOne(sht3.Cells(i, 5).value)
End If
End Sub
Public Function IncreaseWithOne(strValue As String) As String
Dim myVal As Long
myVal = Split(strValue, "-")(1)
IncreaseWithOne = Split(strValue, "-")(0) & "-" & Format(myVal + 1, "0000")
End Function
But it is really better, if you edit your question to what you want. E.g., you want to split the string 25-00001, cast to integer and increment the second part and return 25-00002. Because adding integer to string is not supported by any programming language.
From your other question (linked at bottom), we know that the digits you want to increment are always the right-hand 4 characters, so you could use Right to isolate the numerical part. I also think you have now taken a different approach and are storing the increment value separately. For reference though, this is how you could have done it:
Dim myString as String
myString = "25-0003"
' Assume there is always a single dash before the number to increment
' This means we can use Split to create two parts, before and after "-"
Dim myVal as Integer
myVal = Val(Split(myString, "-")(1))
' >> myVal = 3
myVal = myVal + 1
' >> myVal = 4
myString = Split(myString,"-")(0) & "-" & Format(myVal, "0000")
' >> myString = "25-0004"
So to edit your actual code, implementing the above code as a function, it becomes
Sub ThisIsYourSub()
If k > 0 Then
Sht1.Cells(erow, 3) = IncrementString( sht3.Cells(i, 5).value )
Sht1.Cells(erow, 4) = IncrementString( sht3.Cells(i, 6).value )
Sht1.Cells(erow, 1) = IncrementString( Sht1.Cells(erow - 1, 1).value)
End If
End Sub
Function IncrementString(ByVal myString as String) as String
' You should have some error handling in here!
Dim myVal as Integer
myVal = Val(Split(myString, "-")(1)) + 1
IncrementString = Split(myString,"-")(0) & "-" & Format(myVal, "0000")
End Function
Split Documentation:
https://msdn.microsoft.com/en-us/library/office/gg278528.aspx
Your other question, including details on using the Format function as above:
Standard pattern of string is like 16-000q. Use leading zeros to create 4 digit string from q

Calculate duration of non-continuous overlapping time intervals

I am trying to calculate the total duration of overlap between multiple events. Each event can overlap with multiple other events in any arrangement. I need to calculate the total amount of time any single event overlaps with any other event. The data I have looks like this.
event timeStart timeEnd
1 15:00 22:00
2 12:00 18:00
3 20:00 23:00
4 16:00 17:00
5 10:00 14:00
Output:
event timeOverlap
1 05:00 '03:00 (1,2) + 02:00 (1,3)
2 04:00 '03:00 (1,2) + 01:00 (2,4)
3 02:00 '02:00 (1,3)
4 01:00 '01:00 (2,4)
5 02:00 '02:00 (2,5)
I'm trying to do this in Excel VBA. My main problem right now is finding a way to sum up discontinuous overlaps, e.g. event 1 or event 2. Any help would be appreciated.
Edit: To clarify, I would like to avoid double counting, which is why I didn't include the overlap between (1,4) in the calculation for event 1. The output should show the sum of the overlaps that would result in the largest overlap duration.
Here's part of the code I'm using. Right now it calculates the longest continuous overlap between multiple events. It doesn't sum up discontinuous overlaps.
'DECLARE VARIABLES
Dim timeStart() As Date 'start times of cases
Dim timeEnd() As Date 'end times of cases
Dim ovlpStart() As Double 'start times of overlap regions for cases
Dim ovlpEnd() As Double 'end times of overlap regions for cases
Dim totalRows As Long 'total number of cases`
'RETRIEVE NUMBER OF ROWS
totalRows = WorksheetFunction.CountA(Columns(1))
'STORE COLUMN DATA FROM EXCEL SHEET INTO ARRAYS
ReDim timeStart(1 To totalRows)
ReDim timeEnd(1 To totalRows)
ReDim ovlpStart(1 To totalRows)
ReDim ovlpEnd(1 To totalRows)
'FILL IN ARRAYS WITH DATA FROM SPREADSHEET
For i = 2 To totalRows
timeStart(i) = Cells(i, 3).Value
timeEnd(i) = Cells(i, 4).Value
'Initialize ovlpStart and ovlpEnd
ovlpStart(i) = 1
ovlpEnd(i) = 0
Next
'FILL IN CONCURRENCE COLUMN WITH ALL ZEROS TO START
For i = 2 To totalRows
Cells(i, 6).Value = "0"
Next
'SEARCH FOR CONCURRENT TIME INTERVALS
For i = 2 To totalRows
For j = (i + 1) To totalRows
'Check if the times overlap b/w cases i and j
Dim diff1 As Double
Dim diff2 As Double
diff1 = timeEnd(j) - timeStart(i)
diff2 = timeEnd(i) - timeStart(j)
If diff1 > 0 And diff2 > 0 Then
'Mark cases i and j as concurrent in spreadsheet
Cells(i, 6).Value = "1"
Cells(j, 6).Value = "1"
'Determine overlap start and end b/w cases i and j, store as x and y
Dim x As Double
Dim y As Double
If timeStart(i) > timeStart(j) Then
x = timeStart(i)
Else
x = timeStart(j)
End If
If timeEnd(i) < timeEnd(j) Then
y = timeEnd(i)
Else
y = timeEnd(j)
End If
'Update ovlpStart and ovlpEnd values for cases i and j if overlap region has increased for either
If x < ovlpStart(i) Then
ovlpStart(i) = x
End If
If x < ovlpStart(j) Then
ovlpStart(j) = x
End If
If y > ovlpEnd(i) Then
ovlpEnd(i) = y
End If
If y > ovlpEnd(j) Then
ovlpEnd(j) = y
End If
End If
Next
Next
'DETERMINE DURATION OF OVERLAP, PRINT ONTO SPREADSHEET
Dim ovlpDuration As Double
For i = 2 To totalRows
ovlpDuration = ovlpEnd(i) - ovlpStart(i)
If Not ovlpDuration Then
Cells(i, 7).Value = ovlpDuration
Else
Cells(i, 7).Value = 0
End If
Next`
The Excel Application object has the Intersect method available. If you treat the hours as imaginary rows on an imaginary worksheet and calculate the rows.count of a possible intersection between them, you can use that integer as the hours interval in a TimeSerial function.
Loose Overlap with Intersect
Sub overlapHours()
Dim i As Long, j As Long, ohrs As Double
With Worksheets("Sheet7")
For i = 2 To .Cells(Rows.Count, "C").End(xlUp).Row
ohrs = 0
For j = 2 To .Cells(Rows.Count, "C").End(xlUp).Row
If j <> i And Not Intersect(Range(Hour(.Cells(i, "B").Value2) & ":" & Hour(.Cells(i, "C").Value2)), _
Range(Hour(.Cells(j, "B").Value2) & ":" & Hour(.Cells(j, "C").Value2))) Is Nothing Then
ohrs = ohrs + TimeSerial(Intersect(Range(Hour(.Cells(i, "B").Value2) & ":" & Hour(.Cells(i, "C").Value2)), _
Range(Hour(.Cells(j, "B").Value2) & ":" & Hour(.Cells(j, "C").Value2))).Rows.Count - 1, 0, 0)
End If
Next j
.Cells(i, 4).NumberFormat = "[hh]:mm"
.Cells(i, 4) = ohrs
Next i
End With
End Sub
To avoid repeating the overlap times from one time period to the next, build a Union of the intersects of the imaginary rows. Unions can be discontiguous ranges so we need to cycle through the Range.Areas property to achieve a correct count of the Range.Rows property.
Strict Overlap with Intersect and Union
Sub intersectHours()
Dim a As Long, i As Long, j As Long, rng As Range, ohrs As Double
With Worksheets("Sheet7")
For i = 2 To .Cells(Rows.Count, "C").End(xlUp).Row
ohrs = 0: Set rng = Nothing
For j = 2 To .Cells(Rows.Count, "C").End(xlUp).Row
If j <> i And Not Intersect(.Range(Hour(.Cells(i, "B").Value2) & ":" & Hour(.Cells(i, "C").Value2) - 1), _
.Range(Hour(.Cells(j, "B").Value2) & ":" & Hour(.Cells(j, "C").Value2) - 1)) Is Nothing Then
If rng Is Nothing Then
Set rng = Intersect(.Range(Hour(.Cells(i, "B").Value2) & ":" & Hour(.Cells(i, "C").Value2) - 1), _
.Range(Hour(.Cells(j, "B").Value2) & ":" & Hour(.Cells(j, "C").Value2) - 1))
Else
Set rng = Union(rng, Intersect(.Range(Hour(.Cells(i, "B").Value2) & ":" & Hour(.Cells(i, "C").Value2) - 1), _
.Range(Hour(.Cells(j, "B").Value2) & ":" & Hour(.Cells(j, "C").Value2) - 1)))
End If
End If
Next j
If Not rng Is Nothing Then
For a = 1 To rng.Areas.Count
ohrs = ohrs + TimeSerial(rng.Areas(a).Rows.Count, 0, 0)
Next a
End If
.Cells(i, 6).NumberFormat = "[hh]:mm"
.Cells(i, 6) = ohrs
Next i
End With
End Sub
      
My results differ from the ones you posted for event 2 but I have traced my logic backwards and forwards and cannot see an error.
I can't say I entirely follow your logic. For example, I don't see why 1 & 4 don't overlap.
However, it's looking as though you'd just take the later of the compared start times and the earlier of the compared end times and subtract the latter from the former. If the result is positive then there's an overlap so aggregate the result within a loop.
I'm assuming your time values are in the Time format (ie hh:mm) and therefore Doubles.
The code below hardcodes your ranges so you'll need to adjust that as suits, but at least you could see the logic to get you going:
Dim tStart As Double
Dim tEnd As Double
Dim tDiff As Double
Dim v As Variant
Dim i As Integer
Dim j As Integer
Dim output(1 To 5, 1 To 2) As Variant
v = Sheet1.Range("A2:C6").Value2
For i = 1 To 5
For j = i + 1 To 5
tStart = IIf(v(i, 2) > v(j, 2), v(i, 2), v(j, 2))
tEnd = IIf(v(i, 3) < v(j, 3), v(i, 3), v(j, 3))
tDiff = tEnd - tStart
If tDiff > 0 Then
output(i, 1) = output(i, 1) + tDiff
output(j, 1) = output(j, 1) + tDiff
output(i, 2) = output(i, 2) & i & "&" & j & " "
output(j, 2) = output(j, 2) & i & "&" & j & " "
End If
Next
Next
Sheet1.Range("B9:C13").Value = output

how to insert data from textbox to excel using vb.net?

I'm stuck here, I want to insert the data from 5 textbox to existing excel file in columns. I found code but its inserting by rows. I have below a code that finds the last non empty row and from that row I want to move to the next row and insert data there, for example last row is A2, I want to insert new data to A3, B3, C3, D3, E3.
I can't get the right loop for this.
Dim lRow As Long = 0
Call OpenExcelFile("C:\Users\PB\Desktop\BookRecords.xlsx", 1)
With xlWorkSheet
If EXL.WorksheetFunction.CountA(.Cells) <> 0 Then
lRow = .Cells.Find(What:="*", _
After:=.Range("A2"), _
LookAt:=Excel.XlLookAt.xlPart, _
LookIn:=Excel.XlFindLookIn.xlFormulas, _
SearchOrder:=Excel.XlSearchOrder.xlByRows, _
SearchDirection:=Excel.XlSearchDirection.xlPrevious, _
MatchCase:=False).Row
Else
lRow = 1
End If
lRow += 1
End With
MessageBox.Show("The last row in Sheet1 which has data is " & lRow)
Dim j As Integer
j = 3
For i As Integer = j To 8
xlWorkSheet.Range(xlWorkSheet.Cells(lRow + 1, j).item).Value = txtTitle.Text
xlWorkSheet.Range(xlWorkSheet.Cells(lRow + 1, j).item).Value = txtAuthor.Text
xlWorkSheet.Range(xlWorkSheet.Cells(lRow + 1, j).item).Value = txtEdition.Text
xlWorkSheet.Range(xlWorkSheet.Cells(lRow + 1, j).item).Value = txtPublisher.Text
xlWorkSheet.Range(xlWorkSheet.Cells(lRow + 1, j).item).Value = txtISBN.Text
Next
j += 1
Call SaveAndCloseExcelSub()
Does this help:
Dim j As Integer
j = 3
For i As Integer = j To 8
MsgBox("Cell column: " & ColumnNumberToName(i))
Next
Code to convert numbers to Excel Column Names (A-Z, AA, etc):
Public Shared Function ColumnNumberToName(columnNumber As Int32) As String
Dim dividend As Int32 = columnNumber
Dim columnName As [String] = [String].Empty
Dim modulo As Int32
While dividend > 0
modulo = (dividend - 1) Mod 26
columnName = Convert.ToChar(65 + modulo).ToString() + columnName
dividend = DirectCast(((dividend - modulo) / 26), Int32)
End While
Return columnName
End Function
Public Shared Function ColumnNameToNumber(columnName As [String]) As Int32
If [String].IsNullOrEmpty(columnName) Then
Throw New ArgumentNullException("columnName")
End If
Dim characters As Char() = columnName.ToUpperInvariant().ToCharArray()
Dim sum As Int32 = 0
Dim i As Int32 = 0
While i < characters.Length
sum *= 26
sum += (characters(i) - "A"C + 1)
System.Math.Max(System.Threading.Interlocked.Increment(i),i - 1)
End While
Return sum
End Function
As it is, all your values are being written to the same cell; then you move down a row and do it again. Cells are addressed as (row, column) - so you need to change your code like this:
Dim j As Integer
j = 3
For i As Integer = j To 8
xlWorkSheet.Cells(lRow + i, 1).Value = txtTitle.Text
xlWorkSheet.Cells(lRow + i, 2).Value = txtAuthor.Text
xlWorkSheet.Cells(lRow + i, 3).Value = txtEdition.Text
xlWorkSheet.Cells(lRow + i, 4).Value = txtPublisher.Text
xlWorkSheet.Cells(lRow + i, 5).Value = txtISBN.Text
Next
Not sure if you need to start with i = 3 if you add lRow to it but I'm sure you can work that out.
If you want the order reversed, do this (this example copies only one lot of text... I am beginning to suspect there is no need for the loop)
dim i as Integer
i = 1; ' if you want column A
With xlWorkSheet
.Cells(lRow , i).Value = txtTitle.Text
.Cells(lRow + 1, i).Value = txtAuthor.Text
.Cells(lRow + 2, i).Value = txtEdition.Text
.Cells(lRow + 3, i).value = txtPublisher.Text
.Cells(lRow + 4, i).Value = txtISBN.Text
End With