How to optimize this code? - c#

Surely there has to be many ways to optimize the following code, where I basically have to make sure that a lot of textboxes aren't empty and then read their values:
if (foo1.Text.Length != 0 & bar1.Text.Length != 0)
{
output.Text += myStrings[i] + " / " + foo1.Text + " / " + bar1.Text;
}
if (foo2.Text.Length != 0 & bar2.Text.Length != 0)
{
output.Text += myStrings[i] + " / " + foo2.Text + " / " + bar2.Text;
}
if (foo3.Text.Length != 0 & bar3.Text.Length != 0)
{
output.Text += myStrings[i] + " / " + foo3.Text + " / " + bar3.Text;
}
if (foo4.Text.Length != 0 & bar4.Text.Length != 0)
{
output.Text += myStrings[i] + " / " + foo4.Text + " / " + bar4.Text;
}
if (foo5.Text.Length != 0 & bar5.Text.Length != 0)
{
output.Text += myStrings[i] + " / " + foo5.Text + " / " + bar5.Text;
}
if (foo6.Text.Length != 0 & bar6.Text.Length != 0)
output.Text += myStrings[i] + " / " + foo6.Text + " / " + bar6.Text;
if (foo7.Text.Length != 0 & bar7.Text.Length != 0)
{
output.Text += myStrings[i] + " / " + foo7.Text + " / " + bar7.Text;
}
if (foo8.Text.Length != 0 & bar8.Text.Length != 0)
{
output.Text += myStrings[i] + " / " + foo8.Text + " / " + bar8.Text;
}
if (foo9.Text.Length != 0 & bar9.Text.Length != 0)
{
output.Text += myStrings[i] + " / " + foo9.Text + " / " + bar9.Text;
}
if (foo10.Text.Length != 0 & bar10.Text.Length != 0)
{
output.Text += myStrings[i] + " / " + foo10.Text + " / " + bar10.Text;
}

I would put the repeated elements in arrays and then loop over them.
TextBox[] foos = new TextBox[] { foo1, foo2, foo3, /* etc */ };
TextBox[] bars = new TextBox[] { bar1, bar2, bar3, /* etc */ };
for (int i = 0; i <= 10; i++)
if (foos[i].Text.Length != 0 && bars[i].Text.Length != 0)
output.Text += myStrings[i] + "/" + foos[i].Text + bars[i].Text;
Of course, if the elements are really named sequentially you can fill the arrays by looking up the controls from the form's Controls collection, with the name "foo" + number.ToString().

I would just loop over the Controls collection on which these TextBoxes reside, then filter on TextBox only and do you checks and concat.
I also strongly advice to use a StringBuilder instead of +=.

There are a lot of ways to refactor this. The method you choose will depend on your particular scenario and needs.
Make a function that takes a foo and a bar as a parameter and returns the string, then aggregate that string in a string builder
Put the foos and bars into collections and loop over those collections. In this scenario, arrays would be useful and provide a way to mutually index the arrays.
Take item 2 one step further and create a new class FooBar that holds a foo and a bar together. This way you can create a collection of FooBars and you don't have an implicit association between them anymore, now it's explicit and codified.
Take item 3 one step further and recognize that you're aggregating a string. If you're in a recent version of c#, take advantage of your Map/Reduce in LINQ (.Select().Aggregate()) to transform your FooBars into their corresponding strings, and then to aggregate the strings into output.
This is all just the stuff off the top of my head. If you work at it more, I'm sure you can do even better. :)
(If this is homework, please add a homework tag.)
EDIT:
I can't help but wonder about the design of the UI in general based upon your comment in another post stating that it takes "many seconds" to concatenate the strings together. 10 strings is a pretty trivial amount of time on its own, but this suggests that your outer loop (that's generating i) is fairly long running.
If you're in a position where you have the freedom to make such decisions, are you certain that your UI is actually good for the task at hand? A large collection of pairs of text boxes is a difficult user interface in general. Perhaps a ListView would be more appropriate. It would implicitly contain a collection, so you wouldn't have to deal with this "ten text boxes" silliness and will be an easier UI for your users to follow in general.

Write a function which accepts foo & bar types. Pass all foo1 & bar1 to foo10 and bar10 to the function to get the values. You can also create array of foo and bar and you can loop and call the method to get the string.

foreach (Control ctrl in Page.Controls) {
if (ctrl is TextBox) {
if (ctrl.Text.Length != 0) {
output.Text += myStrings[i] + "/" + ctrl.Text;
}
}
}
Untested , but should work. With this your textboxes could be named anything.

Could you make foo1-foo10 into an array, foo[10], and the same for bar? That would allow you to express this as a simple loop.

Would it be feasible to make a WebControl that has textboxes called foo and bar, and that has a function like:
if (foo.Text.Length != 0 & bar.Text.Length != 0)
return myStrings[i] + " / " + foo.Text + " / " + bar.Text;
else
return string.Empty;
Put ten of those on your page, then use:
output.Text = myControl1.FooBar + myControl2.FooBar + myControl3.FooBar + ...
(Still a bit messy, but not quite so repetitive.)

Related

Converting a void function that returns Console.WriteLine into a string function?

I had some recursive problems to solve (and after some struggle I ended up victorious)
I made the functions (that calculates the result for them) void and after every iteration of the recursive function I called "Console.WriteLine()" to print the line and after I continued with the recursion until a certain condition was met afterwards I called the calculation function into the Main function. Now I want to try to convert them into strings and make them cleaner and then call the function inside Main with Console.WriteLine(). For example the following code.
public static void TowerOfHanoi(int n, char firstRod, char secondRod, char thirdRod)
{
if (n == 0)
{
return;
}
TowerOfHanoi(n - 1, firstRod, thirdRod, secondRod);
Console.WriteLine("From " + firstRod + " to " + secondRod);
TowerOfHanoi(n - 1, thirdRod, secondRod, firstRod);
}
This is for the Tower of Hanoi problem where I have to move a whole stack of discs from a certain rod to another(in my problem from A to B) using using an intermediary rod C.
The rules: I can't have a disc larger on top of a smaller one, so every move I make has to keep the smaller discs above the bigger ones.
I tried to change the function from void to string and add a new empty string in there for example:
string result = ""; and instead of the Console.WriteLine I tried using result+= "From " + firstRod + " to " + secondRod + "\n"; and afterwards call the function into Main using Console.WriteLine. => Here I hit wall.
This is my failed attempt to convert it: If I enter 2 as input it should return:
From A to C
From A to B
From C to B.
but with my failed attempt it returns only From A to B. I know that I should have a variable where I should add all the results after each recursion, but I can't seem to figure it out
public static string TowerOfHanoi(int n, char firstRod, char secondRod, char thirdRod)
{
if (n == 0)
{
return "";
}
TowerOfHanoi(n - 1, firstRod, thirdRod, secondRod);
TowerOfHanoi(n - 1, thirdRod, secondRod, firstRod);
return "From " + firstRod + " to " + secondRod + "\n";
}
Do you have any suggestions on how can I get around this? Thank you in advance!
Your updated code significantly changes the logic of the original code in two ways:
The "from ... to" result is now after both of the recursive calls, whereas previously it was between the two recursive calls.
The result from those recursive calls is entirely ignored. If a method returns a result, and you want that result, you have to capture it in some way.
For example:
var result = string.Empty;
if (n == 0)
{
return result;
}
result += TowerOfHanoi(n - 1, firstRod, thirdRod, secondRod);
result += "From " + firstRod + " to " + secondRod + "\n";
result += TowerOfHanoi(n - 1, thirdRod, secondRod, firstRod);
return result;
You can then start to improve upon the functionality a little bit by using a StringBuilder instead of appending strings:
if (n == 0)
{
return string.Empty;
}
var result = new StringBuilder();
result.Append(TowerOfHanoi(n - 1, firstRod, thirdRod, secondRod));
result.Append("From " + firstRod + " to " + secondRod + "\n");
result.Append(TowerOfHanoi(n - 1, thirdRod, secondRod, firstRod));
return result.ToString();

compare List with different size in C#

Hi I have an application in C# .NET where a person can submit an abstract. It will be a paragraph.
Now if I made any changes on that abstract from my end, It should send the email to that person with the Original abstract and modified abstract. Where in Modified section it should highlight the changes done.
I have written a function for this:
public string[] compareText(string submittedValue,string updatedValue)
{
#region COMPARETEXT
List<string> oldAbstract = submittedValue.Split('.').ToList<string>();
List<string> newAbstract = updatedValue.Split('.').ToList<string>();
string resultOldAbstract = "";
string resultNewAbstract = "";
for (var i = 0; i < (oldAbstract.Count - 1); i++)
{
if (String.Equals(oldAbstract[i], newAbstract[i], StringComparison.Ordinal))
{
resultOldAbstract += oldAbstract[i].ToString() + ".";
resultNewAbstract += newAbstract[i].ToString() + ".";
}
else
{
List<string> oldAbstract1 = oldAbstract[i].Split(' ').ToList<string>();
List<string> newAbstract1 = newAbstract[i].Split(' ').ToList<string>();
if (oldAbstract1.Count == newAbstract1.Count)
{
for (var j = 0; j < (oldAbstract1.Count); j++)
{
if (String.Equals(oldAbstract1[j], newAbstract1[j], StringComparison.Ordinal))
{
if (j < (oldAbstract1.Count - 1))
{
resultOldAbstract += oldAbstract1[j].ToString() + " ";
resultNewAbstract += newAbstract1[j].ToString() + " ";
}
else
{
resultOldAbstract += oldAbstract1[j].ToString() + ".";
resultNewAbstract += newAbstract1[j].ToString() + ".";
}
}
else
{
if (j < (oldAbstract1.Count - 1))
{
resultOldAbstract += oldAbstract1[j].ToString() + " ";
resultNewAbstract += "<span style='background:yellow'>" + newAbstract1[j].ToString() + "</span> ";
}
else
{
resultOldAbstract += oldAbstract1[j].ToString() + ".";
resultNewAbstract += "<span style='background:yellow'>" + newAbstract1[j].ToString() + "</span>.";
}
}
}
}
else
{
resultOldAbstract += oldAbstract[i].ToString() + ".";
resultNewAbstract += "<span style='background:yellow'>" + newAbstract[i].ToString() + "</span>.";
}
}
}
//return resultOldAbstract,resultNewAbstract;
return new[] {resultOldAbstract,resultNewAbstract};
#endregion
}
but it only works when the size of both list are same. For e.g.
****Submitted abstract****
hi This is John. i am 26 year old. I live in New York.
****Updated abstract****
Hi This is John. I am 26 year old. I live in washington.
when I do these changes then It works fine. It highlights the changes done at hi, i, New York.
Here the submitted list and updated list both have same number of elements ( here it is 3 , bcz i am splitting at fullstop '.'). But suppose in my update abstract I add a new line or remove a line:
****Updated abstract****
Hi This is John. I am 26 year old. I live in washington. I am a software engineer.
or
****Updated abstract****
Hi This is John. I am 26 year old.
then it does not work because the size of list is different and in for loop it throws index error.
Any thoughts ?

why does it appear a blank space between to string concatened c#

public string completeHour(string theTime)
{
string total="";
string[] timeArray = theTime.Split(new[] { ":" }, StringSplitOptions.None);
string h = timeArray[0];
string i = timeArray[1];
string j = timeArray[2];
MessageBox.Show(h + "+" + i + "+" + j);
if (h == " " || i == " " || j == " ")
{
if (h == " ")
{
h = "00";
total = (String.Concat("00",theTime)).Trim();
MessageBox.Show(total);
}
else if (i == " ")
{
i = "00";
total = timeArray[0] + i + timeArray[2];
//MessageBox.Show("m-=" + total);
}
//else if (j == "")
//{
// j = "00";
// theTime = timeArray[0] + timeArray[1] + j;
// MessageBox.Show("s-=" + theTime);
//}
}
return total;
}
Why total is 00 :52:04 (for instance) and not 00:52:04 that was supposed to be?
If you'd like to make sure there are no leading or trailing white characters, you could call
string h = timeArray[0].Trim();
And then instead of checking the value against " ", you could compare it to String.Empty or call h.IsNullOrEmpty().
However I'd strongly recommend you to use simpler approach, using a DateTime object.
DateTime timeObject;
DateTime.TryParse(theTime, out timeObject);
and then just work with Hour, Minute and Second properties. This way you get away from custom parsing and make your code more object-oriented, thus easier to read, instead of juggling multiple string objects.
Best way to avoid this is using Trim() when assigning value to total in following two lines:
total = (String.Concat("00",theTime.Trim())).Trim();
.
.
.
total = timeArray[0].trim() + i + timeArray[2].Trim();
Although I was using a MaskedTextBox I didn't define a custom mask so, anywhere (I think) the system assumed that 'theTime' was the type of DateTime.
So, the result of String.Concat("00",theTime) was '00 :32:99', for instance.
I´ve solved it by using the variables h, i and j instead of theTime.
Using a DateTime variable was not appropriated because I want to allow the user to insert NULL values for the hours or for the minutes.

Better way of doing it - GetFiles - c#

I'm trying to get all files in a directory but I want them associated with numbers. Now, I have this:
string[] ficheiro = Directory.GetFiles(#"C:\Users\David\Documents\Jogos\Jogos de emuladores\Roms GB\", "*.gba");
{
Console.WriteLine ("F1" + " - " + Path.GetFileNameWithoutExtension (ficheiro[0]));
}
Console.ReadKey ();
When I reach 10 files I will have a shortcut to flip a page to get more files (10 per page). I will list all files by hand. Like this:
Console.WriteLine ("F2" + " - " + Path.GetFileNameWithoutExtension (ficheiro[1]));
Console.WriteLine ("F3" + " - " + Path.GetFileNameWithoutExtension (ficheiro[2]));
Is there a better way of doing it?
You need to use a loop. You cannot do all of them "by hand" because you do not necessarily know how many there are.
var files = Directory.GetFiles(#"C:\Your\Directory\Path", "*.gba");
var count = 0;
foreach (var file in files)
{
if (count % 10 == 0 && count != 0)
{
Console.ReadLine();
}
count++;
Console.WriteLine("F{0} - {1}", count, Path.GetFileNameWithoutExtension(file));
}
Console.ReadLine();
You can iterate through the array with a for-loop :
string[] ficheiros = Directory.GetFiles(#"C:\Users\David\Documents\Jogos\Jogos de emuladores\Roms GB\", "*.gba");
for (int i = 0; i < ficheiros.Length; i++)
{
Console.WriteLine("F{0} - {1}", i + 1, Path.GetFileNameWithoutExtension(ficheiros[i]));
}
Console.ReadKey();
The key is to identify the repeating part and extract a pattern from it :
//only these changed V V
Console.WriteLine ("F2" + " - " + Path.GetFileNameWithoutExtension (ficheiro[1]));
Console.WriteLine ("F3" + " - " + Path.GetFileNameWithoutExtension (ficheiro[2]));
// just replace them and put it inside an appropriate loop, in this case a for-loop
for(int i = 0; i < ficheiro.Length; i++)
Console.WriteLine ("F" + (i+1) + " - " + Path.GetFileNameWithoutExtension (ficheiro[i]));
int i = 0;
var ficheiro = from s in Directory.GetFiles(#"C:\temp\", "*.*")
select ("F"+ i++ + "-" + s);

Vertical scroll Scintilla Textbox during Text Changed event

Setting a Scintilla.Net textbox with a string and scrolling to last line doesn't work.
This Q & A How make autoscroll in Scintilla? has the answer but it wont work at the same time as setting the text.
Bare bones repro:
private void button1_Click(object sender, EventArgs e)
{
string s = RandomString(400);
scintilla1.Text = s + " " + s + " " + s + " " + s + " " + s;
scintilla1.Scrolling.ScrollBy(0, 10000); //<-doesn't work (but does work eg in a Button2_click)
}
private static Random random = new Random((int)DateTime.Now.Ticks);
private string RandomString(int size)
{
StringBuilder builder = new StringBuilder();
char ch;
for (int i = 0; i < size; i++)
{
ch = Convert.ToChar(Convert.ToInt32(Math.Floor(26 * random.NextDouble() + 65)));
builder.Append(ch);
}
return builder.ToString();
}
Does anyone know how to scroll vertically down to end line after setting the text?
Well you can try to put Refresh() after adding the text;
scintilla1.Text = s + " " + s + " " + s + " " + s + " " + s;
scintilla1.Refresh();
for this case i found out that you will need to Refresh() twice depend on the length of the string you put on the textbox.
For anyone wondering in the end I ditched Scintilla in favor of ICSharpCode.TextEditor. <- This one was a little unstable so I used the Digitalrune version of the ICsharp.TextEditor
I found enhancing the ICSharpCode.TextEditor was trivial compared with Scintilla.
Another huge benefit of ICSharpCode.TextEditor is that allows you to customize/build your own Syntax Highlighting, eg: https://github.com/icsharpcode/SharpDevelop/wiki/Syntax-highlighting

Categories