Okay, well let's say I have a variable list of items. It can be any number of items. Each item can be either 0,1,2,3, or 4. So I make a loop.
foreach(item in allitems)
{
if (item == 0) continue;
do stuff for items 1-4.
}
Let's say that every single item it goes through is 0. Well what if I want to execute a specific line of code in that case? Of course I could do something like
int count = 0
foreach(item in allitems)
{
if (item == 0) {count++; continue;}
do stuff for items 1-4.
}
if(count == allitems.Count())
{
do stuff
}
But I always felt cheap using count variables to do something like this. Is there any thing I can do that doesn't feel like duct-taping a solution together?
There's no need to use a count here - just keep a flag which is set if you get past the check, rather than within the check:
bool anyNonZeroItems = false;
foreach(item in allitems)
{
if (item == 0)
{
continue;
}
anyNonZeroItems = true;
// Whatever else
}
if (!anyNonZeroItems)
{
// Everything was 0 (or the collection was empty)
}
You can use Enumerable.All to check if all items in a List satisfy a condition.
in this case something like
if (allItems.All(i => i == 0) {
//do stuff
}
Incidentally in your example you have (if item = 0) and this should be if (item == 0)
What you currently have is perfectly acceptable. I use that kind of pattern all the time.
One thing I would suggest is making count into a bool unless there's an actually a difference between when count == 11 andcount > 1`
This is a pretty common problem, but you propose an odd solution. Why not just use a boolean to indicate state?
bool branchExecuted = false;
foreach(item in allitems)
{
if (item == 0)
{
branchExecuted = true;
continue;
}
//do stuff for items 1-4.
}
if(!branchExecuted)
{
//do stuff if we never hit that line
}
Using this instead of a LINQ / convenience function to operate on the list will only cost you a single boolean and you only have to iterate over your list once.
Related
So I am trying to loop though items that are in a listbox in my application. The list box will allow you to select multiple items to which I have a method tied to each item in the listbox. I have a counter variable incremented each time the loop works.When I use the foreach loop with the switch statement below, it does the first item correct, but then loops through the same item again. I know I am missing something as it is supposed to go to the next item in the listbox and not the same item.
string reportname = lstbxReports.SelectedValue.ToString();
int i = 0;
foreach (var report in reportname)
{
switch (reportname)
{
case "Overview":
{
if (i < 1)
{
PrintOverview(filename);
}
else if (i >= 1)
{
PrintOverviewAppend(filename);
}
break;
}
case "Sources":
{
if (i < 1)
{
PrintSource(filename);
}
else if (i >= 1)
{
PrintSourceAppend(filename);
}
break;
}
}
i++
Any thoughts or suggestions on how I can get the foreach loop to go to the next item in the selected listbox?
Also, this is just a snippet as I have about 11 case items to loop through.
You probably want to switch on report, not reportname.
foreach(string item in listBox.Items)
{
}
?
Depends on how you setup the data source for the listbox though (I'm assuming this is WinForm?). If you created it by adding .Items or using the designer then this will work. However if you've used .DataSource then it wont work.
I'd personally have a
List<string> list = SomeMethodWhereIMakeTheList();
and set that to:
listbox.DataSource = list;
then I wouldn't even have to touch the ListBox to mess with the contents:
list.ForEach(...)
Don't do the print logic in a foreach. Split out the data then print such this (note I changed the name of reportname to reportnames to signify a list of items)
string reportnames = lstbxReports.SelectedValue.ToString();
var firstReport = reportnames.First(); // No error checking here, would use FirstOrDefault with null checks.
if (firstReport == "OverView")
PrintOverview(filename);
else
PrintSource(filename);
// Now print out the rest
reportnames.Skip(1)
.ToList()
.ForEach(rp =>
{
if (rp == "OverView")
PrintOverviewAppend(filename);
else
PrintSourceAppend(filename);
});
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Foreach loop, determine which is the last iteration of the loop
foreach (DataRowView row in orderedTable.DefaultView)
{
if(lasttime) do-something;
}
orderedtable is a datatable
does anyone know how to find out whether we are on the last foreach iteration? please keep in mind that i do have duplicates in orderedtable
The correct method that works in all cases is to use the IEnumerator<T> directly:
using (var enumerator = orderedTable.DefaultView.GetEnumerator())
{
if (enumerator.MoveNext())
{
bool isLast;
do
{
var current = enumerator.Current;
isLast = !enumerator.MoveNext();
//Do stuff here
} while (!isLast);
}
}
This method works even if your collection doesn't have a Count property, and even if it does, this method will be more efficient if the Count property is slow.
The foreach construct does not know such a thing, since it applies equally to unbounded lists. It just has no way of knowing what is a last item.
You can iterate the manual way as well, though:
for (int i = 0; i < orderedTable.DefaultView.Count; i++) {
DataRowView row = orderedTable.DefaultView[i];
if (i == orderedTable.DefaulView.Count - 1) {
// dosomething
}
}
An alternative approach which I don't think anyone posted. This works well if you don't know the count ahead of time.
DataRowView lastRow;
foreach (DataRowView row in orderedTable.DefaultView)
{
// Do something...
lastRow = row;
}
if (lastRow != null)
{
// Do something with last row
}
You will have to use a regular for loop if you want to have different behavior on the last item.
for (int i = 0; i < orderedTable.DefaultView.Count; i++)
{
//do stuff
if (i == orderedTable.DefaultView.Count - 1)
{
//do additional special stuff
}
}
It's worth noting that "the other Skeet" has an implementation for a "smart enumerable" which supports a Last property. See the article here: http://msmvps.com/blogs/jon_skeet/archive/2007/07/27/smart-enumerations.aspx
With this you could write something like this (I might get the details wrong, haven't tried it out myself):
foreach (SmartEnumerable<DataRowView> item in new SmartEnumerable<DataRowView>(orderedTable.DefaultView))
{
DataRowView row = item.Value;
if(item.IsLast)
{
///do special stuff
}
}
Instead of using foreach get the IEnumerator. If MoveNext returns null the previous was the last one.
for would work too of course.
You could possibly do something like the following:
foreach (DataRowView row in orderedTable.DefaultView)
{
if(row == orderedTable.DefaultView.Last()) do-something;
}
But its pretty inefficient.
If you're concerned in keeping track of your iteration, why not use a for instead or a foreach? Then you can simply do the following:
for(int i = 0; i<orderedTable.DefaultView.Count-1;i++)
{
if(i==orderedTable.DefaultView.Count-1)
{
// Last Row
}
}
The code you have posted is identical to:
if (orderedTable.DefaultView.Rows.Count > 0)
do-something;
If that does not do what you want, you will have to explain what lastTime does.
If I understand your question, does this help?
int lastrow = 0;
foreach (DataRow row in table.Rows) // Loop over the rows.
{
lastrow++;
// Do Something
if (lastrow == (table.Rows.Count - 1))
{
// Do something else
}
}
I am trying to do this:
foreach (Settings sets in MySets)
{
if (sets.pName == item.SubItems[2].Text)
{
var ss = new SettingsForm(sets);
if (ss.ShowDialog() == DialogResult.OK)
{
if (ss.ResultSave)
{
sets = ss.getSettings();
}
}
return;
}
}
But since the sets spawned variable is readonly, I cant override it.
I would also like to do something like this
foreach (Settings sets in MySets)
{
if(sets.pName == someName)
sets.RemoveFromList();
}
How can I accomplish this? Lists have a very nice Add() method, but they forgot the rest :(
You can use:
MySets.RemoveAll(sets => sets.pName == someName);
to remove all the items that satisfy a specific condition.
If you want to grab all the items satisfying a condition without touching the original list, you can try:
List<Settings> selectedItems = MySets.FindAll(sets => sets.pName == someName);
foreach loops don't work here as trying to change the underlying list will cause an exception in the next iteration of the loop. Of course, you can use a for loop and manually index the list. However, you should be very careful not to miss any items in the process of removing an item from the list (since the index of all the following items will get decremented if an element is removed):
for (int i = 0; i < MySets.Count; ++i) {
var sets = MySets[i]; // simulate `foreach` current variable
// The rest of the code will be pretty much unchanged.
// Now, you can set `MySets[i]` to a new object if you wish so:
// MySets[i] = new Settings();
//
// If you need to remove the item from a list and need to continue processing
// the next item: (decrementing the index var is important here)
// MySets.RemoveAt(i--);
// continue;
if (sets.pName == item.SubItems[2].Text)
{
var ss = new SettingsForm(sets);
if (ss.ShowDialog() == DialogResult.OK)
{
if (ss.ResultSave)
{
// Assigning to `sets` is not useful. Directly modify the list:
MySets[i] = ss.getSettings();
}
}
return;
}
}
You can't do it in a 'regular' for loop?
I got this:
DataTable dtEntity = CreateDataTable();
drEntity = dtEntity.NewRow();
Then I add data to the row (or not).
Lots of code, really don't know if there's anything inside the row.
Depends on the input (i am importing from some files).
I'd like to do something like:
if (drEntity`s EVERY CELL IS NOT EMPTY)
{
dtEntity.Rows.Add(drEntity);
}
else
{
//don't add, will create a new one (drEntity = dtEntity.NewRow();)
}
Is there some nice way to check if the DataRow's every cell is empty?
Or I should foreach, and check them one by one?
A simple method along the lines of:
bool AreAllColumnsEmpty(DataRow dr)
{
if (dr == null)
{
return true;
}
else
{
foreach(var value in dr.ItemArray)
{
if (value != null)
{
return false;
}
}
return true;
}
}
Should give you what you're after, and to make it "nice" (as there's nothing as far as I'm aware, in the Framework), you could wrap it up as an extension method, and then your resultant code would be:
if (datarow.AreAllColumnsEmpty())
{
}
else
{
}
I created an extension method (gosh I wish Java had these) called IsEmpty as follows:
public static bool IsEmpty(this DataRow row)
{
return row == null || row.ItemArray.All(i => i is DBNull);
}
The other answers here are correct. I just felt mine lent brevity in its succinct use of Linq to Objects. BTW, this is really useful in conjunction with Excel parsing since users may tack on a row down the page (thousands of lines) with no regard to how that affects parsing the data.
In the same class, I put any other helpers I found useful, like parsers so that if the field contains text that you know should be a number, you can parse it fluently. Minor pro tip for anyone new to the idea. (Anyone at SO, really? Nah!)
With that in mind, here is an enhanced version:
public static bool IsEmpty(this DataRow row)
{
return row == null || row.ItemArray.All(i => i.IsNullEquivalent());
}
public static bool IsNullEquivalent(this object value)
{
return value == null
|| value is DBNull
|| string.IsNullOrWhiteSpace(value.ToString());
}
Now you have another useful helper, IsNullEquivalent which can be used in this context and any other, too. You could extend this to include things like "n/a" or "TBD" if you know that your data has placeholders like that.
I prefer approach of Tommy Carlier, but with a little change.
foreach (DataColumn column in row.Table.Columns)
if (!row.IsNull(column))
return false;
return true;
I suppose this approach looks more simple and cleaner.
public static bool AreAllCellsEmpty(DataRow row)
{
if (row == null) throw new ArgumentNullException("row");
for (int i = row.Table.Columns.Count - 1; i >= 0; i--)
if (!row.IsNull(i))
return false;
return true;
}
I know this has been answered already and it's an old question, but here's an extension method to do the same:
public static class DataExtensions
{
public static bool AreAllCellsEmpty(this DataRow row)
{
var itemArray = row.ItemArray;
if(itemArray==null)
return true;
return itemArray.All(x => string.IsNullOrWhiteSpace(x.ToString()));
}
}
And you use it like so:
if (dr.AreAllCellsEmpty())
// etc
You could use this:
if(drEntity.ItemArray.Where(c => IsNotEmpty(c)).ToArray().Length == 0)
{
// Row is empty
}
IsNotEmpty(cell) would be your own implementation, checking whether the data is null or empty, based on what type of data is in the cell. If it's a simple string, it could end up looking something like this:
if(drEntity.ItemArray.Where(c => c != null && !c.Equals("")).ToArray().Length == 0)
{
// Row is empty
}
else
{
// Row is not empty
}
Still, it essentially checks each cell for emptiness, and lets you know whether all cells in the row are empty.
DataTable.NewRow will initialize each field to:
the default value for each DataColumn (DataColumn.DefaultValue)
except for auto-increment columns (DataColumn.AutoIncrement == true), which will be initialized to the next auto-increment value.
and expression columns (DataColumn.Expression.Length > 0) are also a special case; the default value will depend on the default values of columns on which the expression is calculated.
So you should probably be checking something like:
bool isDirty = false;
for (int i=0; i<table.Columns.Count; i++)
{
if (table.Columns[i].Expression.Length > 0) continue;
if (table.Columns[i].AutoIncrement) continue;
if (row[i] != table.Columns[i].DefaultValue) isDirty = true;
}
I'll leave the LINQ version as an exercise :)
AFAIK, there is no method that does this in the framework. Even if there was support for something like this in the framework, it would essentially be doing the same thing. And that would be looking at each cell in the DataRow to see if it is empty.
I did it like this:
var listOfRows = new List<DataRow>();
foreach (var row in resultTable.Rows.Cast<DataRow>())
{
var isEmpty = row.ItemArray.All(x => x == null || (x!= null && string.IsNullOrWhiteSpace(x.ToString())));
if (!isEmpty)
{
listOfRows.Add(row);
}
}
Maybe a better solution would be to add an extra column that is automatically set to 1 on each row. As soon as there is an element that is not null change it to a 0.
then
If(drEntitity.rows[i].coulmn[8] = 1)
{
dtEntity.Rows.Add(drEntity);
}
else
{
//don't add, will create a new one (drEntity = dtEntity.NewRow();)
}
To delete null and also empty entries Try this
foreach (var column in drEntitity.Columns.Cast<DataColumn>().ToArray())
{
if (drEntitity.AsEnumerable().All(dr => dr.IsNull(column) | string.IsNullOrEmpty( dr[column].ToString())))
drEntitity.Columns.Remove(column);
}
this.entityModel.Entities is a source to my datagrid(agdatagrid).
I have kept AutoGenerateColumns="False".
i have 6 columns in my agdatgrid
i want 6th column to be visible depending on the data of that column..ie., if any row of that column contains the data then it should be visible and if none of the row contains the data for that column it should be invisible.
So i have written a foreach loop but it takes more time to get ui loaded if the data is large. so is there any other way ?
foreach (BrowserEntity _browseEntity in this.entityModel.Entities)
{
if (_browseEntity.State != null && this.entityModel.Entities.Count>0)
{
this.grid.DataSource = this.entityModel.Entities;
this.grid.Columns[6].Visible = true;
break;
}
else
{
this.grid.DataSource = this.entityModel.Entities;
this.grid.Columns[6].Visible = false;
}
}
First look at the logic of what you're writing. You're checking whether the count of a collection is greater than zero inside a loop that iterates over it; this will always return true as the loop will not run if the collection contains anything. So what you're actually writing is this, when code that either always returns true or which cannot execute is removed:
foreach (BrowserEntity _browseEntity in this.entityModel.Entities)
{
if (_browseEntity.State != null)
{
this.grid.DataSource = this.entityModel.Entities;
this.grid.Columns[6].Visible = true;
break;
}
}
So you're assigning the data source a number of times, and never setting Visible to false, whereas I think what you're actually trying to write is something like this:
// bind the grid but hide column 6
this.grid.DataSource = this.entityModel.Entities;
this.grid.Columns[6].Visible = false;
// if there is any state then show column 6
foreach (BrowserEntity _browseEntity in this.entityModel.Entities)
{
if (_browseEntity.State != null)
{
this.grid.Columns[6].Visible = true;
break;
}
}
Alternatively, using Linq, this could be written as the following, which achieves the same thing but is much clearer:
this.grid.DataSource = this.entityModel.Entities;
this.grid.Columns[6].Visible = this.entityModel.Entities.Any(e => e.State != null);
I'm not an expert on this...but why are you resetting the DataSource every time?
bool isColumnVisible = false;
this.grid.DataSource = this.entityModel.Entities;
foreach (BrowserEntity _browseEntity in this.entityModel.Entities)
{
if (_browseEntity.State != null && this.entityModel.Entities.Count>0)
{
isColumnVisible = true;
break;
}
}
this.grid.Columns[6].Visible = isColumnVisible;
I think this should be faster...at least I hope so.
I'm not a silverlight developer, but why do you check for "this.entityModel.Entities.Count>0" in the foreach loop? I would assume the count is always >0 when you enter the loop, isn't it?