Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 5 years ago.
Improve this question
How to increase performance (it takes about 10 seconds) of this foreach loop
foreach (var item in pList)
{
var foundedItem = source.FirstOrDefault(x => x.LongRecordId == item.LongRecordId);
if (foundedItem != null && !selectionList.Contains(foundedItem))
{
foundedItem.Readonly = pReadonly;
selectionList.Add(foundedItem);
}
}
In case source as well as pList are long, you may try converting source into a Dictionary:
// Provinding that all LongRecordId are distinct
var dict = source
.ToDictionary(item => item.LongRecordId, item => item);
...
foreach (var item in pList) {
MyRecord foundItem = null; //TODO: Put the right type here
// Instead of O(N) - FirstOrDefault we have O(1) TryGetValue
if (dict.TryGetValue(item.LongRecordId, out foundItem)) {
foundItem.Readonly = pReadonly;
selectionList.Add(foundItem);
}
}
Edit: In case you want to ensure that selectionList contains distinct items only (see Ferhat Sayan's comment) try HashSet
...
HashSet<MyRecord> selectedHash = new HashSet<MyRecord>(selectionList);
foreach (var item in pList) {
MyRecord foundItem null; //TODO: Put the right type here
// Instead of O(N) - FirstOrDefault we have O(1) TryGetValue
if (dict.TryGetValue(item.LongRecordId, out foundItem)) {
foundItem.Readonly = pReadonly;
selectedHash.Add(foundItem);
}
}
selectionList = selectedHash.ToList();
I suggest to profile that piece of code.
I guess the most time consuming call is the FirstOrDefault-Extension Method.
To use for instead of foreach is unlikely to grant you much if any performance gains.
Most probably your problems stems from your context variables, maybe a very large source list?
Overall, this code section is maybe not the best place to look for performance improvements. If this is the only place, you should think about a redesign.
If you have very large lists and do not fear concurrency issues you could go the parallel or multi-processing route. parallel.foreach is a cheap way to do some tests.
The use of a Dictionary instead of a List should speedup things. If you go with a HashSet (to yield the benefit of uniqunes) be aware to implement a proper IEqualityComparer, or you could even lose performance when you add a huge number of items relying on the DefaultComparer.
Related
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 1 year ago.
Improve this question
Still learning C# - is it possible to loop through elements of a string array and compare it with the values in a list of objects? eg:
var allFolks = new List<Folks>();
allFolks = Folks.GetAll();
string[] enteredNames = Array.ConvertAll(inputNames.Text.Split(','), p => p.Trim());
foreach (var eName in enteredNames)
{
//if eName is not in the list of allFolks throw an exception
if (!allFolks.Name.Contains(eName))
throw new Exception ("Name not found");
}
What would be the best way to compare each entered name (stored in an array) with the names in the list of type Folks? Is it possible to use Lambda Expression in the example above?
string[] enteredNames = inputNames.Split(',');
foreach (var eName in enteredNames)
{
if (!allFolks.Any(e => e.Name.Contains(eName.Trim()))
{
throw new Exception("Name not found");
}
}
Taking a string of inputNames and calling .Split(',') will separate the string by each comma and save them into a string[].
Then if (!allFolks.Any(e => e.Name.Contains(eName))) will throw the exception if eName does not exist within any object in the List<Folks>.
It's a difficult to asnwer for "what is the best" question: the best in performance, memory, readability?
I suggest using Linq in order to query the collections:
using System.Linq;
...
// Do we have any unknown name (i.e. any namy name except folks' names)?
bool hasUnknownName = inputNames
.Text
.Split(',', StringSplitOptions.TrimEntries)
.Except(allFolks.Select(folk => folk.Name))
.Any();
if (hasUnknownName)
throw ... //TODO: don't throw Exception, but some derived class
Linq solution
Often is more readable
Faster then initial one (if allFolks and inputNames are large)
Edit: As Eric J. puts in the comment below, it's possible to improve performance when allFolks is large and has duplicates. We can, for instance, efficiently compare with (precomputed) unique names only:
// We precompute unique names to test
HashSet<string> uniqueNames = new HashSet<string>(allFolks
.Select(folk => folk.Name));
...
bool hasUnknownName = inputNames
.Text
.Split(',', StringSplitOptions.TrimEntries)
.Any(name => !uniqueNames.Contains(name));
if (hasUnknownName)
throw ... //TODO: don't throw Exception, but some derived class
If I am to infer your requirements, I think you wish to validate a list of names, held as strings, and check to ensure each one matches the Name of one of your Folk objects.
You can do it with LINQ this way:
bool invalid = enteredNames.Any( x => !allFolks.Any( y => y.Name == x) );
For a large list of Folk objects, you'll get better performance if you extract the unique set of names to a variable of its own.
var knownGoodNames = allFolks.Select( x => x.Name ).ToHashSet();
bool invalid = enteredNames.Any( x => !knownGoodNames.Contains(x) );
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 5 years ago.
Improve this question
So i have a let's say 100 statements in C#.
CCU_O.MWT.DRSa09_DrEmrgOpn.DRSa09_DrEmrgOpnCst.DCU01_IEmergOpenAct.Force(false);
CCU_O.MWT.DRSa09_DrEmrgOpn.DRSa09_DrEmrgOpnCst.DCU02_IEmergOpenAct.Force(false);
CCU_O.MWT.DRSa09_DrEmrgOpn.DRSa09_DrEmrgOpnCst.DCU03_IEmergOpenAct.Force(false);
And so on till DCU100. I want to run a loop in that way that I can access all the statements DCU01..DCU100.
EDIT : Everything before Force. is a signal container. That's why can't use Array or List (No overload method).
You can use reflection
var obj = CCU_O.MWT.DRSa09_DrEmrgOpn.DRSa09_DrEmrgOpnCst;
for(int i = 0; i < yourCount; i++){
var prop = obj.GetType().GetProperties().FirstOrDefault(x => x.Name == string.Format("DCU{0}_IEmergOpenAct", i));
if(prop != null){
var propValue = (YourObjectType)prop.GetValue(CCU_O.MWT.DRSa09_DrEmrgOpn.DRSa09_DrEmrgOpnCst);
propValue.Force(False);
}
}
Maybe you need to format the i variable to "00" or something in the string.Format() call
If CCU_O.MWT.DRSa09_DrEmrgOpn.DRSa09_DrEmrgOpnCst.DCU01_IEmergOpenAct is a type name (instead of a member), then you can try the following approach:
IEnumerable<MethodInfo> methods =
Enumerable.Range(1, 100)
.Select(i => $"CCU_O.MWT.DRSa09_DrEmrgOpn.DRSa09_DrEmrgOpnCst.DCU{i:D2}_IEmergOpenAct")
.Select(t => Type.GetType(t))
.Select(t => t.GetMethod("Force", BindingFlags.Public | BindingFlags.Static));
foreach (MethodInfo force in methods)
force.Invoke(null, new object[] { false });
Option 1
Useful if you don't mind writing the whole list once and need it multiple times.
Put it into all individual items into a List/Array and loop over it.
var list = new List<IEmergOpenAct>() { // I am guessing a type here
CCU_O.MWT.DRSa09_DrEmrgOpn.DRSa09_DrEmrgOpnCst.DCU01_IEmergOpenAct,
CCU_O.MWT.DRSa09_DrEmrgOpn.DRSa09_DrEmrgOpnCst.DCU02_IEmergOpenAct,
CCU_O.MWT.DRSa09_DrEmrgOpn.DRSa09_DrEmrgOpnCst.DCU03_IEmergOpenAct,
};
foreach (var act in list)
{
act.Force(false);
}
Option 2
Useful if you don't want to type the whole list but they follow a unique pattern.
Open the Type/Namespace DRSa09_DrEmrgOpnCst via Reflection and get all Types that match the "DCU??_IEmergOpenAct" pattern. Put them into a list like in option 1 and loop over them as shown above.
Current Code:
For each element in the MapEntryTable, check the properties IsDisplayedColumn and IsReturnColumn and if they are true then add the element to another set of lists, its running time would be O(n), there would be many elements with both properties as false, so will not get added to any of the lists in the loop.
foreach (var mapEntry in MapEntryTable)
{
if (mapEntry.IsDisplayedColumn)
Type1.DisplayColumnId.Add(mapEntry.OutputColumnId);
if (mapEntry.IsReturnColumn)
Type1.ReturnColumnId.Add(mapEntry.OutputColumnId);
}
Following is the Linq version of doing the same:
MapEntryTable.Where(x => x.IsDisplayedColumn == true).ToList().ForEach(mapEntry => Type1.DisplayColumnId.Add(mapEntry.OutputColumnId));
MapEntryTable.Where(x => x.IsReturnColumn == true).ToList().ForEach(mapEntry => Type1.ReturnColumnId.Add(mapEntry.OutputColumnId));
I am converting all such foreach code to linq, as I am learning it, but my question is:
Do I get any advantage of Linq conversion in this case or is it a disadvantage ?
Is there a better way to do the same using Linq
UPDATE:
Consider the condition where out of 1000 elements in the list 80% have both properties false, then does where provides me a benefit of quickly finding elements with a given condition.
Type1 is a custom type with set of List<int> structures, DisplayColumnId and ReturnColumnId
ForEach ins't a LINQ method. It's a method of List. And not only is it not a part of LINQ, it's very much against the very values and patterns of LINQ. Eric Lippet explains this in a blog post that was written when he was a principle developer on the C# compiler team.
Your "LINQ" approach also:
Completely unnecessarily copies all of the items to be added into a list, which is both wasteful in time and memory and also conflicts with LINQ's goals of deferred execution when executing queries.
Isn't actually a query with the exception of the Where operator. You're acting on the items in the query, rather than performing a query. LINQ is a querying tool, not a tool for manipulating data sets.
You're iterating the source sequence twice. This may or may not be a problem, depending on what the source sequence actually is and what the costs of iterating it are.
A solution that uses LINQ as much as is it is designed for would be to use it like so:
foreach (var mapEntry in MapEntryTable.Where(entry => mapEntry.IsDisplayedColumn))
list1.DisplayColumnId.Add(mapEntry.OutputColumnId);
foreach (var mapEntry in MapEntryTable.Where(entry => mapEntry.IsReturnColumn))
list2.ReturnColumnId.Add(mapEntry.OutputColumnId);
I would say stick with the original way with the foreach loop, since you are only iterating through the list 1 time over.
also your linq should look more like this:
list1.DisplayColumnId.AddRange(MapEntryTable.Where(x => x.IsDisplayedColumn).Select(mapEntry => mapEntry.OutputColumnId));
list2.ReturnColumnId.AddRange(MapEntryTable.Where(x => x.IsReturnColumn).Select(mapEntry => mapEntry.OutputColumnId));
The performance of foreach vs Linq ForEach are almost exactly the same, within nano seconds of each other. Assuming you have the same internal logic in the loop in both versions when testing.
However a for loop, outperforms both by a LARGE margin. for(int i; i < count; ++i) is much faster than both. Because a for loop doesn't rely on an IEnumerable implementation (overhead). The for loop compiles to x86 register index/jump code. It maintains an incrementor, and then it's up to you to retrieve the item by it's index in the loop.
Using a Linq ForEach loop though does have a big disadvantage. You cannot break out of the loop. If you need to do that you have to maintain a boolean like "breakLoop = false", set it to true, and have each recursive exit if breakLoop is true... Bad performing there. Secondly you cannot use continue, instead you use "return".
I never use Linq's foreach loop.
If you are dealing with linq, e.g.
List<Thing> things = .....;
var oldThings = things.Where(p.DateTime.Year < DateTime.Now.Year);
That internally will foreach with linq and give you back only the items with a year less than the current year. Cool..
But if I am doing this:
List<Thing> things = new List<Thing>();
foreach(XElement node in Results) {
things.Add(new Thing(node));
}
I don't need to use a linq for each loop. Even if I did...
foreach(var node in thingNodes.Where(p => p.NodeType == "Thing") {
if (node.Ignore) {
continue;
}
thing.Add(node);
}
even though I could write that cleaner like
foreach(var node in thingNodes.Where(p => p.NodeType == "Thing" && !node.Ignore) {
thing.Add(node);
}
There is no real reason I can think of to do this..>
things.ForEach(thing => {
//do something
//can't break
//can't continue
return; //<- continue
});
And if I want the fastest loop possible,
for (int i = 0; i < things.Count; ++i) {
var thing = things[i];
//do something
}
Will be faster.
Your LINQ isn't quite right as you're converting the results of Where to a List and then pseudo-iterating over those results with ForEach to add to another list. Use ToList or AddRange for converting or adding sequences to lists.
Example, where overwriting list1 (if it were actually a List<T>):
list1 = MapEntryTable.Where(x => x.IsDisplayedColumn == true)
.Select(mapEntry => mapEntry.OutputColumnId).ToList();
or to append:
list1.AddRange(MapEntryTable.Where(x => x.IsDisplayedColumn == true)
.Select(mapEntry => mapEntry.OutputColumnId));
In C#, to do what you want functionally in one call, you have to write your own partition method. If you are open to using F#, you can use List.Partition<'T>
https://msdn.microsoft.com/en-us/library/ee353782.aspx
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 8 years ago.
Improve this question
I have the following loop:
List<Reminders> reminds = new List<Reminders>();
//...
foreach (Reminders remind in reminds)
{
//....
reminds.Insert(id, new Reminders() { Title = remind.Title, Content = remind.Content, Checked = true });
}
However, an error occurs in the foreach loop.
foreach (Reminders remind in reminds)
If I remove the reminds.Insert statement, the error no longer occurs. I'm trying to update some entires inside of the foreach loop. What's causing the error?
Change your Code to this:
List<Reminders> reminds = new List<Reminders>();
...
foreach (Reminders remind in reminds.ToList())
{
....
reminds.Insert(id, new Reminders() { Title = remind.Title, Content = remind.Content, Checked = true });
}
Please note the .ToList() behind reminds.
Explanation: You are not allowed to modify a collection while it is enumerated in an foreach. The .ToList() will create another temporary collection which will be constrant during the foreach loop.
It's true, you are iterating in the same list. You need to create a temporary list, and add the elements in that temp list in the cycle. After, when the foreach finish, you need to use the method AddRange:
reminds.AddRange(tempList);
If you want to update some entries then you shoudn't add new ones just set the property Checked to true of each entry:
List<Reminders> reminds = new List<Reminders>();
...
foreach (Reminders remind in reminds)
{
....
remind.Checked = true;
}
You must not modify the list that you are iterating.
No, You can't insert into an item while iterating through it. Your results will be wrong.
You will need to create a temporary list and do an AddRange() after.
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 8 years ago.
Improve this question
static IEnumerable<Tuple<Double, Double>> GetGreatest(List<List<Tuple<double,double>>> lst)
{
var tempHead = lst[0][0];
for (int i = 1; i < lst.Count; i++)
{
if (i != lst.Count - 1)
{
var previousHead = lst[i - 1][0];
var currentHead = lst[i][0];
if (previousHead.Item2 != currentHead.Item1)
{
yield return Tuple.Create(tempHead.Item1, previousHead.Item2);
tempHead = currentHead;
}
}
else yield return Tuple.Create(tempHead.Item1, lst[i][0].Item2);
}
}
I'm trying to write this in a more functional way so I can easier integrate it into projects in other languages like Scala or F#, my issue is that I've been struggling with it for over an hour, and I can't seem to turn it into anything usable, at least not in scala.
Question: Could I get some hints that point me in the right direction? So I can un-stuck myself...
Clarification: To clear up some possible confusion about naming and such
This is how it's being used:
var lst = new List<Tuple<double,double>>{
Tuple.Create(3.22, 3.29), Tuple.Create(3.22, 4.05), Tuple.Create(3.22, 4.12),
Tuple.Create(3.29, 4.05), Tuple.Create(3.29, 4.12),
Tuple.Create(4.05, 4.12),
Tuple.Create( 9.06, 9.13),Tuple.Create( 9.06, 9.20),Tuple.Create( 9.06, 9.27),
Tuple.Create( 9.13, 9.20),Tuple.Create( 9.13, 9.27),Tuple.Create( 9.13,10.04),
Tuple.Create( 9.20, 9.27),Tuple.Create( 9.20,10.04),Tuple.Create( 9.20,10.11),
Tuple.Create( 9.27,10.04),Tuple.Create( 9.27,10.11),Tuple.Create( 9.27,10.18),
Tuple.Create(10.04,10.11),Tuple.Create(10.04,10.18),Tuple.Create(10.04,10.25),
Tuple.Create(10.11,10.18),Tuple.Create(10.11,10.25),Tuple.Create(10.11,11.01),
Tuple.Create(10.18,10.25),Tuple.Create(10.18,11.01),Tuple.Create(10.18,11.08),
Tuple.Create(10.25,11.01),Tuple.Create(10.25,11.08),Tuple.Create(10.25,11.15),
Tuple.Create(11.01,11.08),Tuple.Create(11.01,11.15),Tuple.Create(11.01,11.22),
Tuple.Create(11.08,11.15),Tuple.Create(11.08,11.22),Tuple.Create(11.08,11.29),
Tuple.Create(11.15,11.22),Tuple.Create(11.15,11.29),Tuple.Create(11.15,12.06),
Tuple.Create(11.22,11.29),Tuple.Create(11.22,12.06),Tuple.Create(11.22,12.13),
Tuple.Create(11.29,12.06),Tuple.Create(11.29,12.13),Tuple.Create(11.29,12.20),
Tuple.Create(12.06,12.13),Tuple.Create(12.06,12.20),Tuple.Create(12.06,12.27),
Tuple.Create(12.13,12.20),Tuple.Create(12.13,12.27),
Tuple.Create(12.20,12.27),
};
var glist = lst.GroupBy(i => i.Item1).Select(i => i.ToList()).ToList(); // creates list of lists
var greatest = GetGreatest(glist).ToList();
which in the end (in this case) will produce 2 tuples (3.22, 4.12) and (9.06, 12.27)
thus in a sense, getting the greatest number in Item2
Note that the data is always ordered sequentially, thus the next item is always going to be bigger than the previous one, thus there's no need for a comparison
The Purpose of this mess is to get the first and last number in any non-overlapping group of numbers, so if you look in the collection above, you can see that before the break I have the numbers 3.22, 3.29, 4.05, and 4.12 all of them overlapping in the tuples, in the sense that (3.22, 3.29) contains 3.29, which is the first element of the tuple below
what the method does is return a tuple containing the first and last non-overlapping number in each "group" of tuples
The reason I ignore everything but the first item in the sub-list, is because I can see that Item2 of the first element is the same as Item1 in the next one (I've written the list so that each line corresponds to a sublist, to make it easier), for that reason there's no reason to include the rest of the list
why then include the rest of the list in the first place you ask? no my choice... this is (a model of) data from a server, it's structured how it is, there's really nothing I can do
what the program does is look for gaps, breaks in the continuation, if it finds a spot where Item2 does NOT equal Item1 then it must mean we've found a gap in the data, and we can safely push Item1 from the first list and Item2 from the last list prior to the gap, into the tuple we want to yield, thus reducing all the overlapping data to only the important start and endpoints, removing all the in-between bloat.
It would appear that your requirements are as follows:
Take the first item from each of the inner lists of tuples; the remaining items in each inner list can be ignored.
Group these tuples into groups while the second item of the previous pair is equal to the next item's first value
Transform each group into a single tuple containing the first value of the first item and the second value of the last item.
We can now create a method call to perform each one of these individual operations.
static IEnumerable<Tuple<Double, Double>> GetGreatest(
List<List<Tuple<double, double>>> list)
{
return list.Select(inner => inner.First())
.GroupWhile((previous, current) => previous.Item2 == current.Item1)
.Select(group => Tuple.Create(group.First().Item1, group.Last().Item2));
}
GroupWhile is defined as follows:
public static IEnumerable<IEnumerable<T>> GroupWhile<T>(
this IEnumerable<T> source, Func<T, T, bool> predicate)
{
using (var iterator = source.GetEnumerator())
{
if (!iterator.MoveNext())
yield break;
List<T> list = new List<T>() { iterator.Current };
T previous = iterator.Current;
while (iterator.MoveNext())
{
if (!predicate(previous, iterator.Current))
{
yield return list;
list = new List<T>();
}
list.Add(iterator.Current);
previous = iterator.Current;
}
yield return list;
}
}