I know that is good practice use LINQ instead of iterative loops, can I modify this code to use LINQ?
List<string> priorsLstIDs = ServiceUtil.extractColumnValuesAsStringVals(tqrPriors,Helper.STUDY_ID);
List<DateTime> priorsLstDates = ServiceUtil.extractColumnValuesAsDateTimeVals(tqrPriors, "STUDY_DATE");
List<PriorElemSt> priorsElemLst = new List<PriorElemSt>(priorsLstIDs.Count);
PriorElemSt elem;
for (int i = 0; i < priorsLstIDs.Count; i++)
{
elem = new PriorElemSt(priorsLstIDs[i], priorsLstDates[i]);
priorsElemLst.Add(elem);
}
return filterStudyPriors(priorsElemLst);
Thanks.
Update: can the call to filterStudyPriors() method can be part of the LINQ?
IEnumerable<PriorElemSt> priorsElemLst = priorsLstIDs.Select((s,i) => new PriorElemSt(s, priorsLstDates[i]));
return filterStudyPriors(priorsElemLst);
You could use the Enumerable.Range method like so:
//first get the range of indexes
var range = Enumerable.Range(0, priorsLstIDs.Count);
//now project a list of elements at each index
var priorsElemLst = range.Select(i => new PriorElemSt(priorsLstIDs[i], priorsLstDates[i])).ToList();
You can use the Zip method
var priorsElemLst = priorsLstIDs.Zip(
priorsLstDates, (i, d) => new PriorElemSt(i, d))
In the above statement i is the item from priorsLstIds and d the item from priorsLstDates. They will be 'zipped' together using their positions in their lists.
it is not a best practice at all but only if you think it will improve the readability against a performance loss.
LINQ-to-Objects generally is going to add some marginal overheads (multiple iterators, etc). It still has to do the loops, and has delegate invokes, and will generally have to do some extra dereferencing to get at captured variables etc.
Is a LINQ statement faster than a 'foreach' loop?
Related
I am new to C# language, I have started learning LINQ in that
So I just want to convert the code using linq. Is there any way to do. The current implementation is not a stylish one.
var list = new List<int>();
for (int index = 0; index < contentList.Count; index++)
{
list.Add(MyClass.GetCorrespondence(module, index));
}
return list;
You could write it like this:
var list = contentList.Select((_, i) => MyClass.GetCorrespondence(module, i)).ToList();
or like this
var list = Enumerable.Range(0,contentList.Count).Select(i => MyClass.GetCorrespondence(module, i)).ToList();
But, honestly, dont do either! Your code is perfectly readable as it is.
If you must use LINQ for this then you can use the overload for Select which "projects each element of a sequence into a new form by incorporating the element's index." e.g:
list.AddRange(contentList.Select((c, index) => MyClass.GetCorrespondence(c, index));
https://learn.microsoft.com/en-us/dotnet/api/system.linq.enumerable.select?view=netframework-4.8
this method work:
var result= contentList.Select((paramter,index)=>MyClass.GetCorrespondence(module,index)).ToList();
If you're desperate to do it with Linq then you could try:
list.AddRange(Enumerable.Range(0, contentList.Count).Select(index => MyClass.GetCorrespondence(module, index)))
or:
list = Enumerable.Range(0, contentList.Count).Select(index => MyClass.GetCorrespondence(module, index)).ToList();
You could also use the ForEach LINQ statement.
contentList.ForEach(x => list.Add(MyClass.GetCorrespondence(module, x)));
EDIT: Any reason why this was down voted?
Here are a list of column names:
var colNames = new List<string> { "colE", "colL", "colO", "colN" };
Based on the position of the column names in the list, I want to make that column's visible index equal to the position of the column name, but without returning a list. In other words, the following lambda expression without "ToList()" at the end:
colNames.Select((x, index) => { grid_ctrl.Columns[x].VisibleIndex = index; return x; }).ToList();
Can this be coded in a one-line lambda expression?
Use a loop to make side-effects. Use queries to compute new data from existing data:
var updates =
colNames.Select((x, index) => new { col = grid_ctrl.Columns[x].VisibleIndex, index })
.ToList();
foreach (var u in updates)
u.col.VisibleIndex = u.index;
Hiding side-effects in queries can make for nasty surprises. We can still use a query to do the bulk of the work.
You could also use List.ForEach to make those side-effects. That approach is not very extensible, however. It is not as general as a query.
Yes, here you are:
colNames.ForEach((x) => grid_ctrl.Columns[x].VisibleIndex = colNames.IndexOf(x));
Note that you need unique strings in your list, otherwise .IndexOf will behave badly.
Unfortunately LINQ .ForEach, as its relative foreach doesn't provide an enumeration index.
I currently have:
List<TimeSpan> times = new List<TimeSpan>();
// ... setup the thousands of times ...
string[] timeStrings = new string[times.Count];
for (int i = 0; i < times.Count; i++)
timeStrings[i] = times[i].ToString("mm.ss");
I feel like there should be an easy way to do this in LINQ, but I can't find it. I got close with times.Select(s => s.ToString("mm.ss").ToArray()), but it just got the first element.
Side note: Are there any good LINQ tutorials out there?
You almost had it:
var timesAsString = times.Select(s => s.ToString("mm.ss")).ToArray()
var timesAsString = times.Select(t => t.ToString("mm.ss")).ToArray();
Your ToArray call is currently on the string, not the enumerable.
This is basically right, the problem is that your ToArray is being called on the string when it should be outside of that (basically a typo);
What you have;
times.Select(s => s.ToString("mm.ss").ToArray())
what you should have;
times.Select(s => s.ToString("mm.ss")).ToArray();
times.Select(s => s.ToString("mm.ss")).ToArray();
I have read couple of articles on Linq and Func<> and understood simple examples but I cannot able to use them in day to day programming. I am keen to know what are the scenarios the LINQ or lambda expressions useful and should be used
For this code: Can I use Linq or lambda expressions
List<int> abundantNumbers = new List<int>();
for (int i = 0; i < 28888; i++)
{
if (i < pta.SumOfDivisors(i))
{
abundantNumbers.Add(i);
}
}
Yes, you can absolutely use LINQ in your example:
var abundantNumbers = Enumerable.Range(0, 28888)
.Where(i => i < pta.SumOfDivisors(i))
.ToList();
Note that it's important that you didn't just post code which added to list - you posted code which showed that the list was empty to start with. In other words, you're creating a list. If you'd merely had code which added to an existing list, I'd have used something like:
var query = Enumerable.Range(0, 28888).Where(i => i < pta.SumOfDivisors(i));
abundantNumbers.AddRange(query);
If you want to do it with the LINQ notation, it would go like this:
var abundantNumbers = (from i in Enumerable.Range(0, 28888)
where i < pta.SumOfDivisors(i)
select i)
.ToList();
(highly simplified example)
I have a generic list of strings:
var strings = new List<string> { "abc", "owla", "paula", "lala", "hop" };
I'm looking for the most efficient way to split this list into a list with elements that meet a condition and a list of elements that don't meet that same condition.
Func<string, bool> condition = s => s.IndexOf("o") > -1;
Predicate<string> kickOut = s => s.IndexOf("o") > -1;
var stringsThatMeetCondition = strings.Where(condition);
strings.RemoveAll(kickOut);
var stringsThatDontMeetCondition = strings;
Is there a way to do this with looping only once through the original list?
Use some linq:
var matches = list.Select(s => s.IndexOf("o") > -1).ToList();
var notMatches = list.Except(matches).ToList();
list.Clear();
list.AddRange(matches);
Update: as has been mentioned in the comments, be careful mutating the list as linq methods try to be on-demand, they will not iterate the list until you start looking into the IEnumerable. However in my case, I call ToList, which effectively causes it to run through the entire list of items.
This would do it:
IEnumerable<T> FilterAndRemove(this List<T> list, Func<T, bool> pred)
{
List<T> filtered = new List<T>();
int i = 0;
while(i < list.Count)
{
if (pred(list[i]))
{
filtered.Add(list[i]);
list.RemoveAt(i);
}
else
{
++i;
}
}
return list;
}
But am sure you have already thought of something similar. Can you please update your answer with the kind of efficiency that you seek?
Note that two filtering runs with pred and !pred over the original list would still be O(n) and not at all inefficient. Especially considering that you'd get the full benefit of lazy evaluation for both result sets. See also Rob's answer.
This algorithm is in O(n^2).
Instead removing each element, you can also collect them in a new list and copy them over to the input list before returning. This will also get you O(n).
One more option for O(n) would be switching to a linked list.
Why not just use
var stringsThatMeetCondition = strings.Where(condition);
var stringsThatDontMeetCondition = strings.Where(x => !condition(x));
Of course, you end up applying the condition to each element in the list twice. To avoid this you might want to write a generic splitting function, which wouldn't be as neat.
Func<string, bool> condition = ...;
var groupedStrings = strings.GroupBy(condition)
var stringsMeetingCondition = groupedStrings.FirstOrDefault(g => g.Key);
var stringsNotMeetingCondition = groupedStrings.FirstOrDefault(g => !g.Key);