Using a 3-column Collection in Excel VBA and searching it - vba

I am building an algorithm in excel vba to search for paths in a network. I am new to programming these types of problems. Please don't suggest alternate software. The problem should be very simple.
Problem Description:
Search a collection of data representing flows on arcs (3 "columns": from, to, flow)
Identify path (start at source, find flow to "to", look up that "to" in the "from" field, find flow to that "to", and so on until another "from" cannot be found) from source to end of each path.
Data looks like this:
fromnode tonode flow
1 2 4
2 3 3
3 4 2
4 5 1
7 6 1
8 7 2
Biggest hurdle:
I am using a Collection to hold this data and setting it with the code below.
Dim y As Collection
Set y = New Collection
y.Add Sheets("FlowDecomp_Solve").Range("fromtoflow").Value
The data gets pulled in, but it looks like this:
(tried a pic, but I'm a new user)
Item 1
Item 1(1)
Item 1 (1,1) 1
Item 1 (1,2) 2
Item 1 (1,3) 4
So it shows that the Collection has 1 item instead of my # of arcs. How do I access the Item1(1,2) type address for the collection. Does each special value have a unique key? How do I search through my collection and remove a specific row after I've used it in the code?
THANK YOU SO MUCH FOR ANY HELP.

After much trial and error, I've decided to make my original data an array and search it like this (d is down the array, a is across):
For d = LBound(arcflow(), 1) To UBound(arcflow(), 1)
For a = LBound(arcflow(), 2) To UBound(arcflow(), 2)
If a = 1 Then
fromnode = arcflow(d, a)
ElseIf a = 2 Then
tonode = arcflow(d, a)
ElseIf a = 3 Then
flow = arcflow(d, a)
'write into node-node matrix
Sheets("FlowDecomp_Solve").Range("nodenodemtrx").Cells(fromnode, tonode).value = 1
End If
Next a
Next d
Then to trace the path, I add the from and to nodes to a collection called Path until it can't find another arc and I write the path out, empty the collection, update the values, and start again.
Hope this helps someone else...

Related

VBA for Excel: Recording and Processing Variable Data

I am taking an excel spreadsheet as an input. Within this spreadsheet there are a series of variables (in my case, nodes, but the distinction is irrelevant). Each node has a series of sub-variables associated with them (essentially, a series of cases), and each case has three float variables associated with them (X, Y, and Z coordinates). It can be visualized like so:
NODE 1 CASE 1 CASE 1 X
CASE 1 Y
CASE 1 Z
CASE 2 CASE 2 X
CASE 2 Y
CASE 2 Z
NODE 2 CASE 1 CASE 1 X
CASE 1 Y
CASE 1 Z
CASE 2 CASE 2 X
CASE 2 Y
CASE 2 Z
See the image below for the format of my input data. Note that there can be potentially hundreds of individual points.
Now here is where i'm stuck:
I need to read this data in, point by point, and process it. The various variables will be processed and outputted onto a new sheet, but i can't come up with an elegant way of reading in the data to be processed. If this were Python, i'd establish a class for the various points and associate methods with that class, but i don't know an analogous version for VBA.
What is the most efficient way to iterate through each point, read in the data associated with each case for each point, process it, and output the end result to a new sheet?
Thanks in advance for any help. This one really has me stuck.
Try this (change “myInputSheetName” and “myOutputSheetName” with your actual inout and output sheet name):
Sub ReadDataIn()
Dim data As Variant
Data = Worksheets(“myInputSheetName”).UsedRange.Value
‘ and now you have a 2D array with as many rows and columns as excel sheet rows and columns with data
Dim iRow As Long, jCol As Long
For iRow = 1 To Ubound(data,1)
For jCol = 1 To Ubound(data,2)
MsgBox data(iRow, jCol)
‘Process your data
Next
Next
‘Write processed data into your output sheet
Worksheets(“myOutputSheetName”).Range(“A1”).Resize(Ubound(data, 1), Ubound(data, 2)).Value = data
End With
End Sub

EXCEL VBA keep changing variables and creating ppt apresentation by interval

Browsing I didnt find nothing especific as I need indeed.
The code I'm looking for, uses "AG6" and "AK6".
AG6 is my client (44 clients) and ak6 my product (4 products).
as a loop, for AG6 = 1 and ak6 = 1 it'll create a power point presentation pasting a certain range [A1:T35], and so on. AG6 still 1 while ak6 <= 4, and everytime ak6 changes it'll create the presentation. when ak6 reaches 4, ag6 goes to 2 and when ak6 reaches 4, ag6 +1 again until 44.
I tried to be more clear I could. I've already done the ppt code but i'm stuck on that loop.
Thank you in advance !!
see ya
Is this what you are looking for? I'm not sure from your title whether your problem is with the looping code or with invoking PowerPoint - what does "use replace code" mean? Anyway, here's a simple nested loop - the "Debug" line is just to show that the loop actually works.
Sub testloop()
Dim client As Integer
Dim product As Integer
With ActiveSheet
For client = 1 To 44
.Range("AG6") = client
For product = 1 To 4
.Range("AK6") = product
'Do Something Here
Debug.Print .Range("AG6") & " - " & .Range("AK6")
Next product
Next client
End With
End Sub
It was my mistake when I was writing another question, forget it !
Exemple:
1
. client as 1 and prod as 1
client as 1 and prod as 2
client as 1 and prod as 3
client as 1 and prod as 4
when prod reaches 4, client goes to 2 and do the same thing.
between every time prod variable changes, i'll create the ppt apresentation.

Treeview.FindNode Not working for me on 2 levels deep

I have a treeview which has a database structure as such:
Id Unit ParentOrganizationalUnitId Level
1 City wide NULL 0
219 Finance Division 218 1
4 City Hall Client Services 3 2
This is is not all the data this is just three levels showing for reference purposes.
For Each row In SearchTag
Dim parentNode As New TreeNode
If row.Level = 0 Then
parentNode.Text = row.SearchTag.ToString
parentNode.Value = row.Id.ToString
trvSearchTag.Nodes.Add(parentNode)
ElseIf row.Level = 1 Then
Dim childNode As New TreeNode
Dim parentchildNode As New TreeNode
childNode.Text = row.SearchTag.ToString
childNode.Value = row.Id.ToString
parentchildNode = trvSearchTag.FindNode(row.ParentSearchTagID)
If Not parentchildNode Is Nothing Then
parentchildNode.ChildNodes.Add(childNode)
End If
ElseIf row.Level = 2 Then
Dim childNode1 As New TreeNode
Dim parentchildNode1 As New TreeNode
childNode1.Text = row.SearchTag.ToString
childNode1.Value = row.Id.ToString
parentchildNode1 = trvSearchTag.FindNode(row.ParentSearchTagID)
If Not parentchildNode1 Is Nothing Then
parentchildNode1.ChildNodes.Add(childNode1)
End If
End If
Next
I have this code ^^^^ which populates the treeview accordingly. the issue is my findnode function only worked on level 0 and level 1 when it goes to find level 2 options it returns nothing? Why is it doing that?
Side notes.
Structure cannot change due to business req
Code can change.
I checked to make sure when it goes looking for a node with a parent id of say 3 that 3 actually did exist in the treeview prior to the search as its added on level 1 accordingly. via debugging the code and also via running the SPROC to see the results exist.
Assuming that you're using the WebForms TreeView control:
The FindNode method takes a path to a node, not just the value of the node, as a parameter.
So, assuming your tree looks something like this:
City wide
Finance Division
City Hall Client Services
... and that each node has the appropriate ID as its Value property, code to find City Hall Client Services would look something like this:
orgTreeView.FindNode("1/219/4")
Just this:
orgTreeView.FindNode("4")
... won't work, because 4 is not a top-level node.

Getting quantity from a unique Item on Excel

I have a spredsheet on Excel and I must get the number of items from a row, somethink like this:
Item1 | Qty1 | Item2 | Qty2 | Item3 | Qty3 | ... | ItemZ | QtyZ |
Into a second sheet, I must populate with these data, but with just two Columns (Items and Qty).
There is any way to do that? I'd rather a solution that uses DGET or VLOOKUP (it seems faster), althought any feasable way to that would make me very happy :D
I've tried use a loop function, using Find + move to the left + copy and paste the qty. The problem was that this tooked like forever (plus my Excel crashed a few times).
So folks, could you help me?
If I understood correctly what you're after, then here's something basic to get you started (it's in VBA, not using Excel functions, but you'll hopefully get the idea):
Public Sub CopyDown()
Dim i As Long
Dim j As Long
j = 1
For i = 1 To Sheet1.Cells(1, Sheet1.Columns.Count).End(xlToLeft).Column Step 2
Sheet2.Cells(j, 1) = Sheet1.Cells(1, i)
Sheet2.Cells(j, 2) = Sheet1.Cells(1, i + 1)
j = j + 1
Next i
End Sub
It's not terribly robust as there's no error checking, but it should work for the case you've described. It assumes Items are arranged across row 1 in odd columns (1, 3, etc.) and Quantities are in even columns (2, 4, etc.) in "Sheet1". Then they are copied to ascending rows (from 1 onwards) in Columns A (for Items) and B (for Quantities) in "Sheet2". Let me know if you need more explanation.

SSIS - Script Component, Split single row to multiple rows (Parent Child Variation)

Thanks in advance for your help. I'm in need of help on writing SSIS script component to delimit single row to multiple rows. There were many helpful blog and post I looked at below:
http://beyondrelational.com/ask/public/questions/1324/ssis-script-component-split-single-row-to-multiple-rows-parent-child-variation.aspx
http://bi-polar23.blogspot.com/2008/06/splitting-delimited-column-in-ssis.html
However, I need a little extra help on coding to complete the project. Basically here's what I want to do.
Input data
ID Item Name
1 Apple01,02,Banana01,02,03
2 Spoon1,2,Fork1,2,3,4
Output data
ParentID ChildID Item Name
1 1 Apple01
1 2 Apple02
1 3 Banana01
1 4 Banana02
1 5 Banana03
2 1 Spoon1
2 2 Spoon2
2 3 Fork1
2 4 Fork2
2 5 Fork3
2 6 Fork4
Below is my attempt to code, but feel free to revise whole if it's illogic. SSIS Asynchronous output is set.
Public Overrides Sub Input0_ProcessInputRow(ByVal Row As Input0Buffer)
Dim posID As Integer, childID As Integer
Dim delimiter As String = ","
Dim txtHolder As String, suffixHolder As String
Dim itemName As String = Row.ItemName
Dim keyField As Integer = Row.ID
If Not (String.IsNullOrEmpty(itemList)) Then
Dim inputListArray() As String = _
itemList.Split(New String() {delimiter}, _
StringSplitOptions.RemoveEmptyEntries)
For Each item As String In inputListArray
Output0Buffer.AddRow()
Output0Buffer.ParentID = keyField
If item.Length >= 3 Then
txtHolder = Trim(item)
Output0Buffer.ItemName = txtHolder
'when item length is less than 3, it's suffix
Else
suffixHolder = Trim(item)
txtHolder = Left(txtHolder.ToString(), Len(txtHolder) _
- Len(suffixHolder)) & suffixHolder.ToString()
Output0Buffer.ItemName = txtHolder
End If
Next
End If
End Sub
The current code produces the following output
ID Item Name
1 Apple01
1 02
1 Banana01
1 02
1 03
2 Spoon1
2 2
2 Fork1
2 2
2 3
2 4
If I come across as pedantic in this response, it is not my intention. Based on the comment "I'm new at coding and having a problem troubleshooting" I wanted to walk through my observations and how I came to them.
Problem analysis
The desire is to split a single row into multiple output rows based on a delimited field associated to the row.
The code as it stands now is generating the appropriate number of rows so you do have the asynchronous part (split) of the script working so that's a plus. What needs to happen is we need to 1) Populate the Child ID column 2) Apply the item prefix to all subsequent row when generating the child items.
I treat most every problem like that. What am I trying to accomplish? What is working? What isn't working? What needs to be done to make it work. Decomposing problems into smaller and smaller problems will eventually result in something you can do.
Code observations
Pasting in the supplied code resulted in an error that itemList was not declared. Based on usage, it seems that it was intended to be itemName.
After fixing that, you should notice the IDE indicating you have 2 unused variables (posID, childID) and that the variable txHolder is used before it's been assigned a value. A null reference exception could result at runtime. My coworker often remarks warnings are errors that haven't grown up yet so my advice to you as a fledgling developer is to pay attention to warnings unless you explicitly expect the compiler to warn you about said scenario.
Getting started
With a choice between solving the Child ID situation versus the name prefix/suffix stuff, I'd start with an easy one, the child id
Generating a surrogate key
That's the fancy title phrase that if you searched on you'd have plenty of hits to ssistalk or sqlis or any of a number of fabulously smart bloggers. Devil of course is knowing what to search on. No where do you ever compute or assign the child id value to the stream which of course is why it isn't showing up there.
We simply need to generate a monotonically increasing number which resets each time the source id changes. I am making an assumption that the inbound ID is unique in the incoming data like a sales invoice number would be unique and we are splitting out the items purchased. However if those IDs were repeated in the dataset, perhaps instead of representing invoice numbers they are salesperson id. Sales Person 1 could have another row in the batch selling vegetables. That's a more complex scenario and we can revisit if that better describes your source data.
There are two parts to generating our surrogate key (again, break problems down into smaller pieces). The first thing to do is make a thing that counts up from 1 to N. You have defined a childId variable to serve this. Initialize this variable (1) and then increment it inside your foreach loop.
Now that we counting, we need to push that value onto the output stream. Putting those two steps together would look like
childID = 1
For Each item As String In inputListArray
Output0Buffer.AddRow()
Output0Buffer.ParentId = keyField
Output0Buffer.ChildId = childID
' There might be VB shorthand for ++
childID = childID + 1
Run the package and success! Scratch the generate surrogate key off the list.
String mashing
I don't know of a fancy term for what needs to be done in the other half of the problem but I needed some title for this section. Given the source data, this one might be harder to get right. You've supplied value of Apple01, Banana01, Spoon1, Fork1. It looks like there's a pattern there (name concatenated with a code) but what it is it? Your code indicates that if it's less than 3, it's a suffix but how do you know what the base is? The first row uses a leading 0 and is two digits long while the second row does not use a leading zero. This is where you need to understand your data. What is the rule for identifying the "code" part of the first row? Some possible algorithms
Force your upstream data providers to provide consistent length codes (I think this has worked once in my 13 years but it never hurts to push back against the source)
Assuming code is always digits, evaluate each character in reverse order testing whether it can be cast to an integer (Handles variable length codes)
Assume the second element in the split array will provide the length of the code. This is the approach you are taking with your code and it actually works.
I made no changes to make the generated item name work beyond fixing the local variables ItemName/itemList. Final code eliminates the warnings by removing PosID and initializing txtHolder to an empty string.
Public Overrides Sub Input0_ProcessInputRow(ByVal Row As Input0Buffer)
Dim childID As Integer
Dim delimiter As String = ","
Dim txtHolder As String = String.Empty, suffixHolder As String
Dim itemName As String = Row.ItemName
Dim keyField As Integer = Row.ID
If Not (String.IsNullOrEmpty(itemName)) Then
Dim inputListArray() As String = _
itemName.Split(New String() {delimiter}, _
StringSplitOptions.RemoveEmptyEntries)
' The inputListArray (our split out field)
' needs to generate values from 1 to N
childID = 1
For Each item As String In inputListArray
Output0Buffer.AddRow()
Output0Buffer.ParentId = keyField
Output0Buffer.ChildId = childID
' There might be VB shorthand for ++
childID = childID + 1
If item.Length >= 3 Then
txtHolder = Trim(item)
Output0Buffer.ItemName = txtHolder
Else
'when item length is less than 3, it's suffix
suffixHolder = Trim(item)
txtHolder = Left(txtHolder.ToString(), Len(txtHolder) _
- Len(suffixHolder)) & suffixHolder.ToString()
Output0Buffer.ItemName = txtHolder
End If
Next
End If
End Sub