Results 1 to 6 of 6

Thread: [RESOLVED] [2008] Avoiding 6 nested for loops

  1. #1

    Thread Starter
    Addicted Member
    Join Date
    Sep 2008
    Posts
    183

    Resolved [RESOLVED] [2008] Avoiding 6 nested for loops

    Alright here's my problem. I had originally programmed this in Python and it ran in a few seconds although I knew it was messy. Now that I'm porting it to VB.Net, it chugs along really slow.

    I get a weekly Excel file with hundreds of invoices that need to be assigned batch letters according to the following heirarchy:

    Employee > Division > CustomerName > ProductCode> Expense Code

    I had made each of these categories into its own for loop. On the innermost loop was a 6th that cycled through every row in the Excel spreadsheet. The program tries one combination on every row, and attaches a letter if the row matches the criteria. If it doesn't, it goes to the parent for loop, tries the next item and increments the letter by one.

    This ran in a matter of seconds on Python, but VB does not like it at all. My VB program is pulling the information for the 5 categories by running 5 SQL queries on the Access database and storing each one in its own DataTable. I have 5 DataTables, each only containing the unique values which provide the foundation for the for loops.

    With a test spreadsheet of 260 rows, the software ends up checking the rows 57,888 times which is a huge waste of processing. Here is a sample of the code which is causing the problem. I only did the first three categories and that's fairly slow.

    Edit- Also wondering if I could stick a SQL query after the customer for loop and run something like "SELECT * FROM testQuery WHERE ASSIGNMENT=" & employee & " AND Division=" & division & " AND Customer=" & customer. I could then determine if the combination even exists. I already have the contents of the SQL query in a DataView in VB, but I'm unsure of how to run a similar query on it.

    s Code:
    1. For Each employee In dbDataSet.Tables("ASSIGNMENT").Rows
    2.             For Each division In dbDataSet.Tables("Division").Rows
    3.                 For Each customer In dbDataSet.Tables("Customer").Rows
    4.  
    5.  
    6.                     'For each row in the upload file
    7.                     For row = 2 To xlSheet.UsedRange.Rows.Count
    8.                         'Determine where in the master table does the current row's PromoID occur. This will allow us
    9.                         'to retrieve all the information for said PromoID such as ProductCode, etc
    10.                         rowLoc = dbDataView.Find(xlArray(row - 2))
    11.  
    12.                         'If a PromoID is not in the Access database then -1 will be returned
    13.                         If rowLoc = -1 Then
    14.  
    15.                             'Otherwise see if the PromoID information from spreadsheet = the current iteration of unique item
    16.  
    17.                         ElseIf dbDataView.Item(rowLoc).Item(5) = employee(0) Then
    18.                             If dbDataView.Item(rowLoc).Item(1) = division(0) Then
    19.                                 If dbDataView.Item(rowLoc).Item(2) = customer(0) Then
    20.  
    21.                                     'If true, apply the letter and set the print flag to true
    22.                                     xlSheet.Cells(row, 26).Value = CStr(Chr(currentLetter))
    23.                                     didPrint = True
    24.                                     ProgressBar1.Increment(1)
    25.                                 End If
    26.                             End If
    27.                         End If
    28.  
    29.                     Next row
    30.                     'If a letter was printed this item then cycle the letter to the next one
    31.                     If didPrint = True Then
    32.                         currentLetter += 1
    33.                     End If
    34.                     didPrint = False
    35.                 Next customer
    36.             Next division
    37.             currentLetter = 65
    38.  
    39.  
    40.  
    41.         Next employee
    Last edited by ElPresidente408; Sep 24th, 2008 at 03:51 PM.

  2. #2
    I'm about to be a PowerPoster! mendhak's Avatar
    Join Date
    Feb 2002
    Location
    Ulaan Baator GooGoo: Frog
    Posts
    38,170

    Re: [2008] Avoiding 6 nested for loops

    Moved at request!

  3. #3
    Code Monkey wild_bill's Avatar
    Join Date
    Mar 2005
    Location
    Montana
    Posts
    2,993

    Re: [2008] Avoiding 6 nested for loops

    The datatable object has a select method, so rather than iterating through all of your tables, you can use the select method to query for results. Also, you can set up a primary key, and use the table's row's find method, which is much faster.
    That is the very essence of human beings and our very unique capability to perform complex reasoning and actually use our perception to further our understanding of things. We like to solve problems. -Kleinma

    Does your code in post #46 look like my code in #45? No, it doesn't. Therefore, wrong is how it looks. - jmcilhinney

  4. #4
    PowerPoster Jenner's Avatar
    Join Date
    Jan 2008
    Location
    Mentor, OH
    Posts
    3,712

    Re: [2008] Avoiding 6 nested for loops

    You can also use LINQ to slice that data pretty easily and return lists based on complex criteria just like a database.
    My CodeBank Submissions: TETRIS using VB.NET2010 and XNA4.0, Strong Encryption Class, Hardware ID Information Class, Generic .NET Data Provider Class, Lambda Function Example, Lat/Long to UTM Conversion Class, Audio Class using BASS.DLL

    Remember to RATE the people who helped you and mark your forum RESOLVED when you're done!

    "Two things are infinite: the universe and human stupidity; and I'm not sure about the universe. "
    - Albert Einstein

  5. #5

    Thread Starter
    Addicted Member
    Join Date
    Sep 2008
    Posts
    183

    Re: [2008] Avoiding 6 nested for loops

    The original code I had posted took on average 8.335 seconds to execute.

    Following the suggestions, I reduced the execution time to 1.566 seconds by adding a primary key to the master table and changing the FOR and IF statements. I also used the find command for the dataRow

    dataRow = dbDataTable.Rows.Find(myArray(row - 2))

    For employee = 0 To dbDataSet.Tables("ASSIGNMENT").Rows.Count - 1

    IF dataRow.Item(5) = dbDataSet.Tables("ASSIGNMENT").Rows(employee).Item(0)


    I reduced the average time to 1.434s by adding a primary key to each of the tables in the DataSet. Any further ideas or is this about as good as it'll get?

    I will keep LINQ in mind but I'm still a novice at VB.Net and trying to stick to the basics first.

    Edit- Started tinkering with Select. Seems like it'll be useful in cutting down un-necessary loops. Will let you know.

    Thanks
    Last edited by ElPresidente408; Sep 25th, 2008 at 11:23 AM.

  6. #6

    Thread Starter
    Addicted Member
    Join Date
    Sep 2008
    Posts
    183

    Re: [2008] Avoiding 6 nested for loops

    The Select command was a HUGE help. I shaved the execution time down to about 0.450 seconds. Right after each FOR statement I added the following lines

    v Code:
    1. selectString = "ASSIGNMENT='" & dbDataSet.Tables("ASSIGNMENT").Rows(employee).Item(0) & "'"
    2.  
    3. If dbDataTable.Select(selectString).Length > 0 Then

    The string builds on itself as it goes through the levels.

    Thanks a lot

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width