I was under the impression that the only difference between Func and Action is that the former has to have a return value.So I thought you can call a recursive linq from either a Func or Action. I am new to C# and I am just experimenting and curious.
So I tried the following to recursively print the nested types within a Type.
Type t = typeof(Lev1);
Action<Type> p1 = null, p2 = null;
p1 = tn =>
{
Console.WriteLine(tn.Name);
tn.GetNestedTypes().Select(x => { p1(x); return x; });
};
p2 = tn =>
{
Console.WriteLine(tn.Name);
tn.GetNestedTypes().ToList().ForEach(x => { p2(x);});
};
p1(t);
Console.WriteLine("=".PadRight(50, '='));
p2(t);
So the result I got was that p1 (which uses recursion from a Func-ie Select) only prints the top level whereas p2 which uses Action-ie Foreach prints all levels.
I thought Func is just a function def so recursion is valid. Sure my understanding is wrong can somebody explain
The reason you see only the top-level in the first implementation is because the Select is lazily evaluated. It only starts returning values when it needs to, for example when you iterate it (or when you call Sum or a number of other functions). If you add a ToList() call after the Select, it will work.
You must force the IEnumerable -- it is lazy! (It needn't always be, but be wary with LINQ methods!)
In this case, you discard the results (and the actions!). Oh, well!
You need to add .ToList() to the first Select() call because Linq functions are lazy. In the second call the recursion works because of List<>.ForEach() (which as the name stands does exactly what foreach statement does).
Related
Let's say I have a list of employee instances, employeeList. I can iterate through them, like this:
IEnumerator enumerator = employeeList.GetEnumerator();
while (enumerator.MoveNext())
{
Console.Write(enumerator.Current + " ");
}
I have three questions:
I have a general idea about how enumerators work, just like iterators in C++. But I don't understand the MoveNext() method (like itr ++ in C++), because the method first checks the condition (whether it is in the last element). Let's say we use enumerator.Current to access the first element: I think it actually has already "moved" to the next element in the list, as MoveNext() has been called. So shouldn't the object that Current points to actually be the second element in the list?
I think it would make sense that we can access the current element when using enumerator.Current. For example, we should be able to use enumerator.Current.name, just like we can use (*itr).name or itr=>name in C++. However, C# looks like it doesn't implement this kind of functionality. So what's the point of using enumerator.Current?
This question is not related to IEnumerator. I just saw some code like this:
IEnumerable<int> result = GetData() ?? Enumerable.Empty<int>;
As a beginner in C#, I only know the && and || operators. What is ???
Read documentation: "After an enumerator is created, the enumerator is positioned before the first element in the collection, and the first call to MoveNext advances the enumerator to the first element of the collection"
The problem with your code is that you assign the enumerator to a non-generic enumerator variable. That works because the generic IEnumerator<T> interface inherits from the non-generic. But that's also the reason why you can't use properties of the Employee-class since the type is Object. You have to cast enumerator.Current to the correct type first.
Therefore it's better to use the generic version (and dipose it properly with using):
using(IEnumerator<Employee> empEnumerator = employeeList.GetEnumerator())
{
while(empEnumerator.MoveNext())
{
// now empEnumerator.Current is the Employee instance without casting
Employee emp = empEnumerator.Current;
string empName = emp.Name; // ...
}
}
You can also use var which works like a placeholder for the real type in C#:
using(var empEnumerator = employeeList.GetEnumerator())
{ ... }
If all you need is to enumerate the whole collection a foreach is more comfortable:
foreach(Employee emp in employeeList)
{
Console.WriteLine(emp.Name);
}
Initially, the enumerator is positioned before the first element (since an enumerable might be empty). Thus, the first invocation of MoveNext moves it to the first element (or returns false, if the enumerable is empty).
You are using the old, non-generic version of IEnumerator, where Current returns an object. You can cast the object to the concrete type and invoke .name, or, even better, use a type for employeeList which returns a strongly typed IEnumerator<Employee> (such as List<Employee>).
This is the null-coalescing operator.
PS: In the future, please create one SO question per question. 1+2 can be seen as related, but 3 definitely isn't.
PPS: If you just want a space-separated list of employee names, you don't need an explicit loop at all:
var names = String.Join(" ", employeeList.Select(e => e.name));
Use IEnumerable just this way:
foreach (var e in employeeList)
{
Console.Write(e + " ");
}
IEnumerable Interface
Exposes an enumerator, which supports a simple iteration over a non-generic collection.
foreach (var employee in employeeList)
{
// do your stuff here, you have full employee object
Console.WriteLine(employee.FirstName);
}
c# null coalescing operator
The ?? operator is called the null-coalescing operator. It returns the left-hand operand if the operand is not null; otherwise it returns the right hand operand.
If I have a list of objects that have the properties fruitName and numFruits and I want to pluralize the fruitName where numFruits is greater than 1, is it possible to do that in a single statement by chaining together Where and Foreach?
Something like:
fruitList.Where(fl => fl.numFruits > 1).ForEach(fl => fl.fruitName = fl.fruitName + "s");
I tried the above and it doesn't work. It complains that System.Collections.Generic.IEnumerable doesn't contain a definition for ForEach.
Typically you want to use foreach the language construct when possible. Eric Lippert has a blog post going into additional detail as to why.
Loops are good when you are doing modifications as it makes finding those modifications easier.
foreach (var fl in fruitList.Where(fl => fl.numFruits > 1))
{
fl.fruitName = fl.fruitName + "s";
}
Is more straightforward and accomplishes the same task.
If you really want a one-liner (it will be harder to maintain) and want to keep the original list intact but only modify some of the elements, you'll have to use a full anonymous function. If you need multiple statements (a block of code), you'll need to include the braces and statement-terminating semicolons like below:
fruitList.ForEach(fl => { fl.fruitName = fl.numFruits > 1 ? fl.fruitName + "s" : fl.fruitName; });
This works on the original list (no subset) and does basically the exact same thing a structured foreach would do.
There's a good blog post by Eric Lippert on why there is no “ForEach” sequence operator extension method, essentially the reason is:
The first reason is that doing so violates the functional programming
principles that all the other sequence operators are based upon.
Clearly the sole purpose of a call to this method is to cause side
effects. The purpose of an expression is to compute a value, not to
cause a side effect. The purpose of a statement is to cause a side
effect. The call site of this thing would look an awful lot like an
expression (though, admittedly, since the method is void-returning,
the expression could only be used in a “statement expression”
context.) It does not sit well with me to make the one and only
sequence operator that is only useful for its side effects.
If you wanted to do this in a single statement you could use a .Select()
var newFruitList = fruitList.Where(fl => fl.numFruits > 1).Select(fl => fl.fruitName + "s");
Like #Tim Schmelter suggested, you can use ToList() to convert to a list and then use the ForEach method on the result returned. Although the ToList() might return a shorter list based on the filter, the original objects themselves would be changed and your fruitList will remain unchanged.
fruitList.Where(fl => fl.numFruits > 1).ToList().ForEach(fl => fl.fruitName = fl.fruitName + "s");
// fruitList still has all elements
You can use the static Array.ForEach method to update the list.
Array.ForEach(fruitList.Where(fl => fl.numFruits > 1).ToArray(), x => { x.fruitName += "s"; });
Given that "append an s" doesn't actually give you the correct answer for many fruits, any approach that does that will give you an incorrect answer, no matter how well it does it.
Consider using a lookup table to map singlular to plurals (and vice versa) instead:
using System;
using System.Collections.Generic;
using System.Linq;
public class Test
{
private static Dictionary<string, string> fruitLookup =
new Dictionary<string, string>
{
{"blueberry", "blueberries"},
{"peach", "peaches"},
{"apple", "apples"}
};
public static void Main()
{
var fruitList = new List<string> {"blueberry", "peach", "apple"};
// Here is your one-line conversion:
var plurals = fruitList.Select(f => fruitLookup[f]).ToList();
foreach (var p in plurals)
{
Console.WriteLine(p);
}
}
}
I'm a beginner at C#.
I have come across this piece of code:
List<RelatedProductViewModel> relatedProductViewModel = vm.RelatedProductID.Select(p => new RelatedProductViewModel { RelatedProductID = p, ProductID = vm.ProductID, Type = vm.Type }).ToList();
vm.RelatedProductID is an int array with just one element (0) with a value of 8666.
So I'm thinking that Select is a method available on int arrays, but I can't find any documentation on this.
Can anybody enlighten me:
What does Select do?
Ultimately, I'm trying to figure out what value is being used for p in the llambda expression - please don't get too technical about llambda expression as I have only just read about them.
Select creates a projection; meaning, you provide a function that takes an int and outputs a something, then for every int in the array it executes the function. It is basically this:
static IEnumerable<TResult> Select<TSource,TResult>(
this IEnumerable<TSource> source, Func<TSource,TResult> selector)
{
foreach(TSource item in source)
yield return selector(source);
}
In your case, the selector for each is:
p => new RelatedProductViewModel { RelatedProductID = p,
ProductID = vm.ProductID, Type = vm.Type }
Meaning: each value p in the array become the RelatedProductID of a new RelatedProductViewModel, with a ProductID and Type set via the "captured" value of vm.
So the output in your example will be a list of length 1, where that single item has a RelatedProductID of 8666.
Select is part of IEnumerable<T>. Arrays automatically implement IEnumerable<T> when they are created, so since it implements it, the .Select() is available from there.
But Select is projecting the results from one set to another. It is returning 1 result per iterated value.
When using .Select on an IQueryable<T>, internally it may work slightly differently. It retrieves them as they are iterated, much like a yield does.
By using ToList() at the end, you are forcing it to enumerate all results in one go. For in memory types this is quick, but for databases or resources that have a latency in retrieving items, this can have a large performance impact.
The code is equivalent (but not exactly the same as the following code):
List<RelatedProductViewModel> relatedProductViewModel
= new List<RelatedProductViewModel>();
foreach (var p in vm.RelatedProductID) {
relatedProductViewModel.Add(
new RelatedProductViewModel {
RelatedProductID = p,
ProductID = vm.ProductID,
Type = vm.Type
}
);
}
The Select projects the items in the source sequence (relatedProductViewModel) into a new sequence of elements. The projected sequence is then converted to a list by ToList() and stored in relatedProductViewModel.
As you can see, using LINQ (the original code) creates much cleaner code.
I got a class called BG which has a property called Name Code.
I instantiate an object called bgList.
Now I am trying to get all the Code of the objects which have their 'Crop' property set to cropName.
I would like to convert the following working code to linq but for the life of me am unable to do that - am quite sure that I am missing something:
List<string> breedingGroupsAndRoles = new List<string>();
for (int i = 0; i < bgList.Count; i++)
{
if (bgList[i].Crop == cropName)
breedingGroupsAndRoles.Add(bgList.[i].Code);
}
The closest I came was this but it only nets me the first item:
breedingGroupsAndRoles.Add(bgrList.Find(c => c.Crop == cropName).Role);
List<string> breedingGroupsAndRoles = bgList
.Where(bg => bg.Crop == cropName)
.Select(bg => bg.Code)
.ToList();
Just for the sake of completeness, the Find method you tried calling on bgList is not part of LINQ, it's a member of the generic List class itself. It only returns the first element matched by the predicate you provide, which is why you were only getting one result. You probably wanted the FindAll method, which returns a list of all matching elements:
List<BG> breedingGroups = bgList.FindAll(c => c.Crop == cropName);
Note that this produces a list of matching BG instances rather than just their Role properties. Depending on how you're processing the results this may be sufficient, otherwise you'll still need LINQ or a loop and a second list to extract the Role values. In any case, an all-LINQ solution such #Tim Schmelter's is likely the better way to go.
I want to invoke Queryable.Where() and get all elements. There's no version of Where() that works without a predicate function. So I have to right this:
var result = table.Where( x => true );
and it works but that feels really stupid to me - x is never used, and there's no "transformation" for the => "arrow" symbol.
Is there a more elegant solution?
You can use the following, which is more elegant:
var result = table;
You could also omit result completely, and use table directly.
Isn't table.Where(x=>true) essentially a noop? I mean, what is the point? You can do use _ instead of x though, which is idiomatic.
table.Where(_=> true);
But really, the following is what you are doing:
for (var item in table)
{
if (true) // your Where() clause..
{
yield item;
}
}
See how it doesn't really make sense?
table.Where( x => true ) is not "returning all elements". It simply returns an enumerable that has enough information to return some subset of elements when it is being enumerated upon. Until you enumerate it, no elements are "returned".
And since this subset is not even proper in this case (i.e. all elements are returned), this is essentially a no-op.
To enumerate over all elements, write a simple foreach, or use ToList or ToArray or if you don't care about actually returning any elements (and just want to enumerate, presumably for side-effects): table.All(x => true) or table.Any(x => false), or even just table.Count().
In this case you would not need to call Where because you are not filtering the Queryable.
If you still wish to call Where and you do this in many places you could define a static Func and reuse that:
public static Func<int, bool> t = ReturnTrue;
public static bool ReturnTrue(int i)
{
return true;
}
table.Where(t);
If you're trying to get a copy of the contents of table instead of a reference,
var result = table.ToList();
but it's not clear if that's really what you're trying to accomplish. Details?