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();
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?
I have one code of employee which is A-B-C-D- . Now I want to search all records which are starting with A- till it rich A-B-C-D-. I have tried below code:
var result = db.Employee.Where(x=> x.EmployeeCode.StartsWith("A-B-C-D-"));
Above code gives me only one record. But I want all records which starts with A- then A-B- then A-B-C- and then equals to A-B-C-D-.
Any hint or idea is appreciated.
Have you tried this?
var result = db.Employee
.Where(x=> x.EmployeeCode.StartsWith("A-")
|| x.EmployeeCode.StartsWith("A-B-")
|| x.EmployeeCode.StartsWith("A-B-C-")
|| x.EmployeeCode.StartsWith("A-B-C-D-");
As you say in the comment that it must be dynamic, then do something like this:
string code = "A-B-C-D-";
var predicates = new List<Expression<Func<Customer,bool>>>();
for (int i = 0; i < code.Length; i++)
{
if (code[i] == '-')
{
var prefix = code.Substring(0, i + 1);
predicates.Add(x => x.EmployeeCode.StartsWith(prefix));
}
}
var oredPredicates = ...; // Keep reading!
...
var result = db.Employee.Where(oredPredicate);
Now, you have a lis of predicates, and have to combine them with || (or). To do so it's a bit messy, but there are solutions, for example like in this SO Q&A's:
Combining two expressions (Expression>)
Combine two Linq lambda expressions
How can I combine two lambda expressions without using Invoke method?
C# how to combine two expressions into a new one?
Once you have all the predicates combined, use it as parameter for your .Where() function.
Unfortunately the most complicated part of combining the expressions is unavoidable, and it's the toughest part to solve this problem, but it works. Please, read the 3 Q&A's, to get insight in what you're doing and get the code that best suits you (beware that using the simple Expression.OrAlso would not directly work, because the x param in each lambda is different for each created expression)
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 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?
I am looking for a way to get the index of all elements in a list from a keyword search within the list. So for example my list has:
Hello World
Programming Rocks
Hello
Hello World
I love C#
Hello
Now from this list of strings, i want to get all the indices of elements that say Hello World. I have tried the following but it only returns the first index it finds that has my search criteria:
for (int i = 0; i< searchInList.Count; i++)
foundHelloWorld[i] = searchInList.IndexOf("Hello World");
Anyone know of a way to do this?
Thanks
searchInList.Select((value, index) => new {value, index})
.Where(a => string.Equals(a.value, "Hello World"))
.Select(a => a.index)
If you're trying to search for more than just "Hello World", you could do
searchInList.Select((value, index) => new {value, index})
.Where(a => stringsToSearchFor.Any(s => string.Equals(a.value, s)))
.Select(a => a.index)
Since you know you're looking for ALL occurrences and therefore you must traverse the entire list anyway, you'll gain a lot of readability over using IndexOf by simply examining each element yourself:
var i=0;
foreach(var value in searchInList)
{
if(value == "Hello World")
foundHelloWorld.Add(i); //foundHelloWorld must be an IList
i++;
}
You can also use an overload of the Linq Select method that incorporate's the element's index in the source collection; this should be highly readable (and thus maintainable) to Linq-experienced programmers:
foundHelloWorld = searchInList
.Select((v,i)=>new {Index = i, Value = v})
.Where(x=>x.Value == "Hello World")
.Select(x=>x.Index)
.ToList();
The above code takes the list and transforms the string into a simple anonymous type incorporating each item's place in the original list. Then, it filters down to only matching elements, and then it projects out the Index (which didn't change through the filtering) into a new List object. However, all this transformation will make this solution perform slower, because this statement will traverse the entire list multiple times.
A little ugly but will work:
var searchInList = new List<string>();
//Populate your list
string stringToLookUp= "Hello world";
var foundHelloWorldIndexes = new List<int>();
for (int i = 0; i < searchInList.Count; i++)
if (searchInList[i].Equals(stringToLookUp))
foundHelloWorldIndexes.Add(i);
The FindAll method for lists is here. The list extension method Where is here.
Both of these will do pretty much exactly what you want and they are pretty easy to use. There are abundant examples of each on the internet but if you need help using them just let me know.