This should be a simple question. All I want to know is if there is a better way of coding this. I want to do a foreach loop for every array, without having to redeclare the foreach loop. Is there a way c# projects this? I was thinking of putting this in a Collection...?
Please, critique my code.
foreach (TextBox tb in vert)
{
if (tb.Text == box.Text)
conflicts.Add(tb);
}
foreach (TextBox tb in hort)
{
if (tb.Text == box.Text)
conflicts.Add(tb);
}
foreach (TextBox tb in cube)
{
if (tb.Text == box.Text)
conflicts.Add(tb);
}
You can use LINQ:
conflicts.AddRange(
vert.Concat(hort).Concat(cube)
.Where(tb => tb.Text == box.Text)
);
I'm assuming that conflicts is a List<TextBox>, which has an AddRange method. If it isn't, you'll need to call Add in a (single) loop.
If you're creating conflicts, (or if it starts empty), you can call .ToList() instead.
Another .net 3.5 approach:-
conflicts.AddRange(from textBox in vert.Concat(hort).Concat(cube)
where textBox.Text == box.Text
select textBox);
If you can't use LINQ for whatever reason (and I highly suggest you do) you could make your array searching a single method. For example:
public void FindConflicts(IEnumerable<TextBox> tbList, IList<TextBox> conflicts, string test)
{
foreach(TextBox tb in tbList)
{
if(tb.Text == test)
{
conflicts.Add(tb);
}
}
}
And then call it like so:
FindConflicts(vert, conflicts, box.Text);
FindConflicts(hort, conflicts, box.Text);
FindConflicts(cube, conflicts, box.Text);
There are of course many ways to write this, but you could also do
foreach (var direction in new[] { vert, hort, cube })
foreach (TextBox tb in direction)
if (tb.Text == box.Text)
conflicts.Add(tb);
var unionResult = vert.Concat(hort).Concat(cube)
foreach(TextBox tb in unionResult)
if(tb.Text == box.Text)
conflicts.Add(tb);
You should be able to use Enumerable.Concat to glue them together if you're using .Net 3.5 or higher.
foreach (TextBox tb in vert.Concat(hort).Concat(cube))
If you try to create Sudoku game(mentioned in comments) first read about Permutation group and Combinatorics.
This will help you to choose more efficient Application Model w/o using foreach on text boxes. Using lazy computation resolve the problem with object reduction but not improve your logics man.
Related
I am trying to do a foreach loop that runs through 3 lists. Here is what I have currently:
foreach (Button btn in appList && sequenceLsit && FunctionList)
{
if (btn.FillColor != Color.White)
{
// Do stuff
}
}
I tried using tuples, but as I understand, they use a separate variable for each list. I need a single variable (btn) for all 3 lists.
A foreach loop enumerates one list. If you have three separate lists then you need to create one list from them first, which can then be enumerated. The simplest way to do that is the Enumerable.Concat extension method:
foreach (Button btn in appList.Concat(sequenceLsit).Concat(FunctionList))
There's a few ways to solve this.
You can:
Iterate through each list one at a time (foreach inside foreach inside foreach) as mentioned by John
Union your lists together if they share the same type (how are your lists declared?) and then iterate through them once with a single foreach loop
Also, you can use LINQ to remove the need for the IF statement, like this:
foreach (var btn in appList.Where(x => x.FillColor != Color.White)) {...}
You can use Enumerable.Concat method
foreach (Button btn in appList.Concat(sequenceLsit).Concat(FunctionList))
{
if (btn.FillColor != Color.White)
{
// Do stuff
}
}
#John provided you with .Concat, but you may be able to solve your problem with a different approach:
Create method that works on a button
var CheckButtons(IEnumerable<Button> buttons)
{
foreach (Button btn in buttons)
{
if (btn.FillColor != Color.White)
{
// Do stuff
}
}
}
...
Call it on your lists:
CheckButtons(appList);
CheckButtons(sequenceLsit);
CheckButtons(FunctionList);
Another solution is to install the System.Interactive package (owned by the dotnetfoundation), and use the EnumerableEx.Concat method. It has this signature:
// Concatenates the input sequences.
public static IEnumerable<TSource> Concat<TSource>(
params IEnumerable<TSource>[] sources);
Usage example:
foreach (Button btn in EnumerableEx.Concat(appList, sequenceList, functionList))
{
//...
You can find the source code of this method here. It's pretty trivial.
Expanding on John's answer, if you're going with LINQ, why not go all the way?
foreach (var btn in appList.Concat(sequenceList).Concat(FunctionList)
.Where(b => b.FillColor != Color.White))
{
// do stuff with btn
}
I am attempting to validate a forms controls to see if they are empty and found an interesting point in my flailing.
List<string> emptycontrols = new List<string>();
foreach (Control control in Mainform.V_Datafield.Controls)
{
if (control.Text.Contains(null))
{
emptycontrols.Add(control.Name);
}
}
if (emptycontrols.Count > 0)
{
MessageBox.Show("Empty fields detected:", emptycontrols.ToString());
}
Above is my mediocre solution and when run it comes up that a control, namely the DateTimePicker control can never be empty and quite rightly so.
Ultimately my question is how would I exclude the DateTimePicker control from the foreach loop so that it will ignore it but continue to check the other controls?
The groupbox (V_datafield) contains:
10 x TextBoxes
1 x RichTextBox
1 x DateTimePicker as mentioned above.
You can always check like following inside your foreach loop
if (control is DateTimePicker)
continue;
You could use is like this:
foreach (Control control in Mainform.V_Datafield.Controls)
if (!(control is DateTimePicker) && string.IsNullOrEmpty(control.Text))
emptycontrols.Add(control.Name);
Or, actually, your loop could be removed using LINQ to become:
var emptyControls = Mainform.V_Datafield.Controls
.Cast<Control>()
.Where(control => !(control is DateTimePicker))
.Where(control => string.IsNullOrEmpty(control.Text))
.Select(control => control.Name);
using two Where to keep the logic from the previous code but they could be merged using &&.
I am new to C# and taking my first course at a University. I think this is an issue with instantiation but here goes with what I am after.
I am wanting to get the value from te.ED w/o having to go through the multiple for each loops, as if the answer is "No" then there is no need to go through the loops and extract multiple data elements (not being shown). Is there a way to check that value BEFORE going through all of the for each loops?
Code is here
TR reply = service.track(request);
foreach (CTD ctd in reply.CTD)
{
foreach (TD td in ctd.TD)
{
if (td.Events != null)
{
foreach (TE te in td.Events)
{
if (te.TimestampSpecified)
{
//This is where the field I am after exists
if (te.ED == "YES")
Console.WriteLine("The answer is yes");
else
Console.WriteLine("The answer is no");
}
}
}
}
}
Per the comment from #Anis Programmer - I believe you are wanting to see the TD element from the class CTD. If that is the case - see below
[System.Xml.Serialization.XmlElementAttribute("TD")]
public TD[] TD {
get { return this.tdf; }
set { this.tdf = value; }
}
Per the answer from #Neel below - I am very close with the syntax
var result = reply.CTD.SelectMany(c1 => c1.TD)
.SelectMany(c2 => c2.Events.Select(c3 => c3.TimestampSpecified));
foreach (var ltr in result)
Console.WriteLine(ltr)
Now the issue is that the foreach loop makes two passes, and the value returned from both is True
What do I need to change in this syntax?
I think you can use a LinQ in a foreach like this:
foreach (
var te in from ctd in reply.CTD
from td in ctd.TD
where td.Events != null
from te in td.Events
where te.TimestampSpecified
select te)
{
Console.WriteLine(te.ED == "YES" ? "The answer is yes" : "The answer is no");
}
What I assumed from the example you have posted that you want to avoid multiple nested foreach loop.
You can use linq to shorten the same.Here is how using lamda expression.
var result = reply
.SelectMany(c1 => c1.CTD)
.SelectMany(c2 => c2.TD)
.SelectMany(c3 => c3.Events.Select(c4 => c4.TimestampSpecified));
Now you just loop on the result and compare with ED value.
I have another question and I can't seem to find anything on Google.
What this program does
This program displays the information from an RSS feed.
Question
How can I load all the items from an Arraylist to a TextBox?
Things I have tried
This is what I have so far:
List<Array> list1 = new List<Array>();
foreach (var item in list1)
{
textBox1.AppendText(item.ToString());
}
Problem
When I do this, the TextBox shows this:
System.String[]System.String[]
Instead of:
Recommended Build for CraftBukkit: 1.2.4-R1.0 (build 2126)
http://dl.bukkit.org/downloads/craftbukkit/view/00993_1.2.4-R1.0/
Does anybody have any idea how this array stuff work?
Do I need to loop through the array and search for specific indexes?
Sorry, but I'm still a little bit new to C#, and sorry for my English I'm Dutch :<.
It looks like you ArrayList contains array of string instead of string. So try this :
foreach (var item in list1.OfType<string[]>().SelectMany(i => i))
{
textBox1.AppendText(item);
}
It seems that item is a string array, so try to implode it:
foreach (var item in list1)
{
textBox1.AppendText(string.Join("", item));
}
Your code is basically a list of array. That's why it is showing system.string[]
Change it to
foreach (var item in list1)
{
textBox1.AppendText(string.Join("", item));
}
It will join your each string[] (i.e. item) in List<> and create it like
firstarrrayfirstitem, firstarrayseconditem
and textbox as
firstarrrayfirstitem, firstarrayseconditem, secondarrayfirstitem, secondarrayseconditem.... and so on.
A better way could be to use a stringbuider for better performance and reduction in a propertychanged event called by the textbox;
System.Text.StringBuilder sb = new System.Text.StringBuilder();
foreach (var item in list1.OfType<string[]>().SelectMany(i => i))
{
sb.Append(item);
}
textBox1.Text = sb.ToString();
Better way:
textBox1.Text = string.Join("", list1.OfType<string[]>().SelectMany(i => i));
This is embedded in another loop, and well, it's pretty slow. Is there a better way to do this?
for(int i=0;i< listView.Items.Count;i++)
{
if(listView.Items[i].SubItems[3].Text == "asdf")
{
}
}
Well there's a nicer way to do it:
foreach (ListViewItem item in listView.Items)
{
if (item.SubItems[3].Text == "asdf")
{
...
}
}
Or you could use LINQ:
var query = listView.Items
.Cast<ListViewItem>()
.Where(item => item.SubItems[3].Text == "asdf");
foreach (var item in query)
{
...
}
I doubt that that will be faster though...
Does your outer loop change the listView? If not, could you do the query once and reuse the results in the outer loop?
In case someone runs across this using WPF, you don't get .SubItems on item when you use foreach (ListViewItem item in listView.Items). Instead, I found I could just use DataRowView and get the value of the cell that way:
foreach (DataRowView drv in listView.Items)
{
if (drv.Row[3].ToString() == "asdf")
{
...
}
}
You do have to add a using System.Data; statement at the top of your class to use it. I found it worked in WPF, and it might in other areas (i.e. WinForms), as well.