Click here to Skip to main content
15,882,063 members
Please Sign up or sign in to vote.
5.00/5 (1 vote)
Hello,

I am writing code to process part numbers from a digital scanner. The digital scanner reads part numbers on a label and if the part is listed in the "datagridview" display of the program then it stores them as "scanned" (not shown here) but if they are not found then it returns an error. This code is designed to catch some of the common errors the scanner sometimes makes to prevent the amount of times the user needs to manually correct it.

I have created a fairly nested loop to accomplish this which may become an issue if there are large sets of data for the system to process. If anyone is able to provide a second set of eyes or some advice on how to optimize this code, I would greatly appreciate your thoughts.

int index;
     index = 0;
     string[] rejected = new string[10];
     foreach (DataGridViewRow row in dgView.Rows)
            {
                Fix:
                if ((string)row.Cells[1].Value != txtScannedIn.Text.Trim())
                {
                    string editedtext; 
                    string originaltext;
                    originaltext = txtScannedIn.Text.Trim();
                    editedtext = ScanFix(txtScannedIn.Text, rejected); //trying to fix the text

                    if ((string)row.Cells[1].Value == editedtext)//this code ensures a correction is right
                    { 
                        MessageBoxButtons buttons = MessageBoxButtons.YesNoCancel;
                        DialogResult result = MessageBox.Show("Unfound scan " + originaltext + " was autocorrected to " + editedtext + "\n" + "\n" + "Press enter to confirm this change" + "\n" + "Press No suggest new part" + "\n" + "Press Cancel to exit dialog", "Suggested Replacement", buttons);
                        if (result == DialogResult.Yes)// Accepted corrections
                                                       // pass through
                        {
                            txtScannedIn.Text = editedtext;
                        }
                        else if (result == DialogResult.No)//Requesting new correction from datagrid
                        {                                   
                            rejected[index] = editedtext;//rejected part is notated for ScanFix method to not suggest again.
                            index++;
                            goto Fix;
                        }
                        else if (result == DialogResult.Cancel)
                        {
                            break;
                        }
                    }
                }



Below is the actual method that fixes the scan. Essentially, it loops through the datagrid and uses a Damerau-Levenshtein string distance algorithm "StringDistance" to determine how many changes away the not found scan is from one in the grid. There are two foreach loops so that it first scans and returns for 1 character replacements and then 2 character ones. If anyone has any advice on a potentially more efficient way to accomplish this I would greatly appreciate your help.

public string ScanFix(string NotFound, string[] rejected)
        {
            
            foreach (DataGridViewRow row in dgView.Rows)
            {
                int guess;
                guess = StringDistance(NotFound, (string)row.Cells[1].Value);//Compare NotFound ID to grid
                if (guess <= 1 && Array.Exists(rejected, element => element == (string)row.Cells[1].Value) == false) 
                {                                                                                                   
                    return (string)row.Cells[1].Value;
                }
                if (NotFound.Contains((string)row.Cells[1].Value) && Array.Exists(rejected, element => element == (string)row.Cells[1].Value) == false)//Sometimes the right part will be scanned with other gunk from the label
                {
                    return (string)row.Cells[1].Value;
                }
            }
            foreach (DataGridViewRow row in dgView.Rows)
            {
                int secondguess;
                secondguess = StringDistance(NotFound, (string)row.Cells[1].Value);
                if (secondguess <= 2 && Array.Exists(rejected, element => element == (string)row.Cells[1].Value) == false)// it then tries the same process for the first two character replacement. 
                {
                    return (string)row.Cells[1].Value;
                }
            }
            return NotFound;
        }


What I have tried:

I have tried creating a separate method for the section of the first block of code that requires the user to confirm the corrected scan, however I don't think this will make it run faster since it requires so many parameters to be passed to it.

I have done extensive research on ways to optimize code/make it run faster but I have been unable to find ways to minimize nested loop usage in either of these code blocks without sacrificing features. I am fairly new to coding and am fully self taught, so I greatly appreciate any and all advice or tips for this code specifically or perhaps something I can look into to learn more about code optimization.

Thank you very much!
Posted
Updated 23-Jul-19 11:24am

Quote:
Advice on minimizing nested loops?

The question starts bad because there is no nested loops in this code!

C#
    Fix:
...
                goto Fix;

Generally speaking, using labels and gotos in code is a bad idea because it makes the code confuse (spaghetti code) and difficult to debug and optimize.
In the rare cases where I resort to gotos is after debugging and optimization when the gotos will result in code speedups.
 
Share this answer
 
Comments
BillWoodruff 23-Jul-19 17:14pm    
Patrice, he is using 'foreach loops, as well as the labels/gotos.
I could fracture my brain in trying to figure out what this complex code is doing :)

A few things jump out at me on quick inspection:

1 you call trim on the input more than once

2 in the loop through the DGV rows, you may call 'ScanFix which appears to do another loop through the rows ?

3 you are reading string)row.Cells[1].Value multiple times: store it in a variable and re-use it.

4 is it possible to traverse the Rows, and create a data structure holding those that need fixing, then, do the fixing on that subset, then update the whatever ?

good luck !
 
Share this answer
 

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900