The query results enumerated more than once - c#

datacontextclass dc=new datacontextclass ();
var news= dc.GetNewsCompany(Int64.Parse ( _idCompany));
if (news.GetEnumerator().MoveNext())
{
foreach (var item in news)
{
drpListNews.Items.Add(item.Title);
}
}
return error:{"The query results cannot be enumerated more than once."}
how can check result != null in LINQ;

Using an enumerator wildly is a bad idea - for example, it needs disposing - which you haven't done (this could lead to a SqlDataReader being left open - not good). In this case, just enumerate it. If there aren't any records, that will be trivial:
if (news!=null)
{
foreach (var item in news)
{
drpListNews.Items.Add(item.Title);
}
}
If you need the data twice, put it in a list:
var news = (blah).ToList();

You are creating the enumerator twice. The first is by calling news.GetEnumerator(), the second one happens behind the scenes in the foreach loop. The first "check" that you make with the call to MoveNext does not seem necessary (you will not go into the foreach unless there are items to iterate over), so just skip the if statement wrapping the loop:
datacontextclass dc = new datacontextclass();
var news = dc.GetNewsCompany(Int64.Parse(_idCompany));
foreach (var item in news)
{
drpListNews.Items.Add(item.Title);
}

Change the second line of your code to
var news= dc.GetNewsCompany(Int64.Parse ( _idCompany)).toList();
it shall remove the issue.

Related

For each loop takes more time to complete

I have a foreach on a list. List length will be huge always like 200K or so.
When i iterate through the list in foreach, the logic within the foreach will be dealing with another collection which is also will be around 1 million items in the list. For each iteration, the collection will be filtered and it needs to update on property and return the collection as it is. But by doing this, the process never gets completed.
foreach(var list in iterationlist)
{
var filteredCollections = collection.where(a=>a.name==list.name);
filteredCollections.foreach(x=>{x.city="xxxx";});
}
What are the ways to make this logic faster ? Currently this implementation takes more than 3 hours but not completing yet
You can use a Lookup (it's similar to Dictionary<key, List<value>>):
var lookup = collection.ToLookup(a => a.name);
foreach (var list in iterationlist)
foreach (var x in lookup[list.name])
x.city="xxxx";
Another option is to hash the names:
var names = new HashSet<string>(iterationlist.Select(x => x.name));
foreach (var x in collection)
if (names.Contains(x.name))
x.city="xxxx";

Alternative to setting values in foreach C#

I'm rather new to MVC/C# and from what I understand, foreach is read-only.
I would like there to be a method that sets the values that are null to false if that method is called.
IQueryable<CurrentMatch> FindTheMatch = (from row in db.CurrentMatches
where row.UserId.ToString() == UserIdentity
where row.MatchID == MatchIdentity
select row);
List<CurrentMatch> SetRemainingValuesToFalse = FindTheMatch.ToList();
I know that the part below wont work, it just demonstrates how I'm trying to achieve what I want to do.
foreach (var Column in SetRemainingValuesToFalse)
{
if (Column == null)
{
Column = false;
}
}
As the row has a large number of properties it wouldn't be scaleable in the future to set each property manually.
You just need to use a standard for loop instead of a foreach. You can't modify the collection inside a foreach because that is how the iterator works. You can however modify values on the objects themselves.
See also: Changing objects value in foreach loop?
I think you have this sort of the wrong way round. If you set that value to false inside any sort of loop, the context is lost when you exit that iteration of the loop.
Instead, what you probably want to do is, when consuming the list, treat nulls as false. You can use the null coalesce operator for this (??)
foreach (var row in FindTheMatch)
{
DoSomethingInterestingWith(row.Column ?? false); // pass false if Column is null.
}
for(int i=0;i<SetRemainingValuesToFalse.length;i++)
{
if (SetRemainingValuesToFalse[i] == null)
{
SetRemainingValuesToFalse[i] = false;
}
}
you are slightly misunderstanding how the foreach is working
foreach(var c in col)
reads as
While col.asEnumerable.HasValues let c = col.asEnumerable.Current
because of this you can't change either the enumerable or its current value with out breaking the loop, however if the enumerable isn't attached to the collection you are changing then you have no problems
ToList for example will clone the collection meaning the enumerable is attached to the clone not the original collection
foreach(var c in col)
col.Remove(c);
will error
foreach(var c in col.ToList())
col.Remove(c);
works fine
like wise
foreach(var c in col)
if(c.Field == null) c.Field = false;
is also fine because you are editing the the content of the current enumerable location not the location itself
however your stated desire of just replacing nulls in a collection is much simpler
col.Select(c=>c??false); //c#6
col.Select(c=>c == null? false : c); //c#<6
as you seem to be working with something akin to a datatable then you could do this
foreach(var row in table.Rows)
foreach(var col in table.Columns)
row[col] = row[col] ?? false;

RemoveAt() not working c#

Even after the RemoveAt() method, my list keeps being the same and I don't even get an error:
foreach (var row in queryCandidates.ToList())
{
try
{
xString = queryCandidates.ToList().ElementAt(i).District;
int.TryParse(xString, out xNumber);
temp = xNumber.Equals(districtNumber);
System.Diagnostics.Debug.Write(temp+ " ");
System.Diagnostics.Debug.Write(i+" ");
if (temp == false)
{
System.Diagnostics.Debug.WriteLine(" i is:"+i);
//not working even when it should
queryCandidates.ToList().RemoveAt(i);
}
}
catch { }
i++;
if (last == i)
{
System.Diagnostics.Debug.WriteLine("before ending loop: ");
return View(queryCandidates.ToList());
}
}
System.Diagnostics.Debug.WriteLine("after ending the loop: ");
return View(queryCandidates.ToList());
ToList() creates a new instance. From this instance you are removing the element. You are not removing the element from the original enumerable.
You should be doing something like this instead:
var candidates = queryCandidates.ToList();
var elementsToRemove = new List<int>();
foreach (var row in candidates)
{
// ...
xString = candidates[i].District;
// ...
if (temp == false)
{
// ...
elementsToRemove.Add(i);
}
}
for(int i = elementsToRemove.Count - 1; i >= 0; --i)
candidates.RemoveAt(elementsToRemove[i]);
return View(candidates);
Please note the use of elementsToRemove. You can't remove the items directly in the loop. This will throw an exception.
Additionally, please note that ToList copies all data. Every single time you call it. It should be obvious that this is not a good idea to do in a loop.
queryCandidates.ToList().RemoveAt(i);
ToList() creates a brand new list, which you then remove an element from, but that list is long gone.
Try:
var newList = queryCandidates.ToList();
for (int i=newList.Count-1; i>=0; i--){
///snip
newList.RemoveAt(i);
Note that I changed your foreach to for (in reverse) because you cannot modify a list while you are iterating over it with foreach.
The ToList() function creates a new List every time you call it. The object is removed from that list, not from the original list. So you should call ToList once before the foreach.
Once you've done that the removeAt() call will work and cause new issues because then you are trying to modify the list from within the foreach loop. So you'll need to rewrite your code in a way which takes the remove out of the loop as well.
Well I'm not exactly sure what Type queryCandidates is, but the reason you are not seeing an update is because you are removing element 'i' from the wrong object. Your ToList() function creates a new object of List type. If you want to keep the change you need to cache that list and use it where you use your original queryCandidates object.
queryCandidates isn't a list.
You're converting it to a list which creates a new instance from which you're removing the item but doesn't affect queryCandidates itself.
You can do:
var queryCandidates myCollection.ToList();
and then
queryCandidates.RemoveAt(i);
What works for me is to remove from the bottom up:
for (int i = list.Count - 1; i > 0; i--)
{
if (list[i][0] == " " || list[i][3] == "0")
list.RemoveAt(i);
}
It makes sense that some items are missed after decreasing the item count.

How to avoid items order change in container after 'Select' extension method usage?

Here is a piece of code:
public class Schema
{
public Schema(List<CountryParticipantsStages> places)
{
Places = places.Select(participant =>(AbstractGeneralParticipants) new GeneralParticipants(participant)).ToList();
}
...
Order of element in source and result lists will be the same if source list is iterated in full. But if if 'Schema' constructor is called in the middle of any iteration then order of elements in 'Places' list will be shifted...
To avoid this I see the only way to use not a 'Select' method but a 'for' loop that will go from 0th element:
public class Schema
{
public Schema(List<CountryParticipantsStages> places)
{
Places = new List<AbstractGeneralParticipants>(places.Count);
for (int i = 0; i < places.Count; i++)
{
Places.Add(new GeneralParticipants(places[i]));
}
}
The 2nd function looks unpleasantly, but I don't see any better way for that. And also, ReSharper suggests me to replays 'for' loop with 'foreach'...
Please advise.
Thanks a lot.
You're wrong to think that if list is being iterated in some place of program, its current position becomes shifted when it is passed as a parameter.
The list does not hold any current index or state. It's the client code that does.
What foreach essentially does is calling GetEnumerator method and uses IEnumerator to move forward and read current value. Once you pass list somewhere else, another foreach gets its own IEnumerator which starts from first element again.
Consider this sample:
void InnerEnumerate (List<int> innerList)
{
foreach (var innerItem in innerList)
Console.WriteLine ("- inner item {0}", innerItem);
}
var outerList = new List<int> { 1, 2, 3 };
foreach (var outerItem in outerList) {
Console.WriteLine ("Outer item {0}", outerItem);
InnerEnumerate (outerList); // pass list as a parameter
}
This is the output:
Outer item 1
- inner item 1
- inner item 2
- inner item 3
Outer item 2
- inner item 1
- inner item 2
- inner item 3
Outer item 3
- inner item 1
- inner item 2
- inner item 3
As you can see, foreach es are independent and don't know anything about each other. They always start from the beginning.
Guess, the best solution will be to avoid relying on the items order in the list. Instead would be better to add additional parameter into 'CountryParticipantsStages' class that will be used to determining its 'position' in list.
In your second example you can use a foreach loop as Resharper suggested:
Places = new List<AbstractGeneralParticipants>(places.Count);
foreach (Place place in places)
{
Places.Add(new GeneralParticipants(place));
}
Or you can also do it using LINQ as in your first example, which is a bit more concise.

HashSet Iterating While Removing Items in C#

I have a hashset in C# that I'm removing from if a condition is met while iterating though the hashset and cannot do this using a foreach loop as below.
foreach (String hashVal in hashset)
{
if (hashVal == "somestring")
{
hash.Remove("somestring");
}
}
So, how can I remove elements while iterating?
Use the RemoveWhere method of HashSet instead:
hashset.RemoveWhere(s => s == "somestring");
You specify a condition/predicate as the parameter to the method. Any item in the hashset that matches the predicate will be removed.
This avoids the problem of modifying the hashset whilst it is being iterated over.
In response to your comment:
's' represents the current item being evaluated from within the hashset.
The above code is equivalent to:
hashset.RemoveWhere(delegate(string s) {return s == "somestring";});
or:
hashset.RemoveWhere(ShouldRemove);
public bool ShouldRemove(string s)
{
return s == "somestring";
}
EDIT:
Something has just occurred to me: since HashSet is a set that contains no duplicate values, just calling hashset.Remove("somestring") will suffice. There is no need to do it in a loop as there will never be more than a single match.
You can't remove items from a collection while looping over it with an enumerator. Two approaches to solve this are:
Loop backwards over the collection using a regular indexed for-loop (which I believe is not an option in the case of a HashSet)
Loop over the collection, add items to be removed to another collection, then loop over the "to-be-deleted"-collection and remove the items:
Example of the second approach:
HashSet<string> hashSet = new HashSet<string>();
hashSet.Add("one");
hashSet.Add("two");
List<string> itemsToRemove = new List<string>();
foreach (var item in hashSet)
{
if (item == "one")
{
itemsToRemove.Add(item);
}
}
foreach (var item in itemsToRemove)
{
hashSet.Remove(item);
}
I would avoid using two foreach loop - one foreach loop is enough:
HashSet<string> anotherHashSet = new HashSet<string>();
foreach (var item in hashSet)
{
if (!shouldBeRemoved)
{
anotherSet.Add(item);
}
}
hashSet = anotherHashSet;
For people who are looking for a way to process elements in a HashSet while removing them, I did it the following way
var set = new HashSet<int> {1, 2, 3};
while (set.Count > 0)
{
var element = set.FirstOrDefault();
Process(element);
set.Remove(element);
}
there is a much simpler solution here.
var mySet = new HashSet<string>();
foreach(var val in mySet.ToArray() {
Console.WriteLine(val);
mySet.Remove(val);
}
.ToArray() already creates a copy for you. you can loop to your hearts content.
Usually when I want to iterate over something and remove values I use:
For (index = last to first)
If(ShouldRemove(index)) Then
Remove(index)

Categories