How do multi-parameter linq expression initialize their parameter? - c#

In this post the solution to the problem is:
list.Where((item, index) => index < list.Count - 1 && list[index + 1] == item)
The concept of multi-parameter (ie (item, index)) is a bit puzzling to me and I don't know the correct word to narrow down my google results. So 1) What is that called? And more importantly, 2) How are the non-enumerable variable initialize? In this case how is index compiled as an int and initialized to 0?
Thanks.

Lambda expressions have various syntax options:
() => ... // no parameters
x => ... // single parameter named x, compiler infers type
(x) => ... // single parameter named x, compiler infers type
(int x) => ... // single parameter named x, explicit type
(x, y) => ... // two parameters, x and y; compiler infers types
(int x, string y) => ... // two parameters, x and y; explicit types
The subtlety here is that Where has an overload that accepts a Func<T, int, bool>, representing the value and index respectively (and returning the bool for the match). So it is the Where implementation that supplies the index - something like:
static class Example
{
public static IEnumerable<T> Where<T>(this IEnumerable<T> source,
Func<T, int, bool> predicate)
{
int index = 0;
foreach (var item in source)
{
if (predicate(item, index++)) yield return item;
}
}
}

When using LINQ, remember that you are passing a method delegate to the Where method. The particular overload of Where that you are invoking takes a method with signature Func<T,int,bool>, and will call this method for each item in list. Internally, this particular method is keeping count for every item iterated, and calling the supplied delegate using this value as the second parameter:
var result=suppliedDelegate(item,count)

This answer's a little more technical... Remember that lambdas are simply syntatic shortcuts to anonymous delegates (which are anonymous methods).
Edit: They can also be expression trees depending on the signature of Where (see Marc's comment).
list.Where((item, index) => index < list.Count - 1 && list[index + 1] == item)
is functionally equivalent to
// inline, no lambdas
list.Where(delegate(item, index) { return index < list.Count - 1 && list[index + 1] == item; });
// if we assign the lambda (delegate) to a local variable:
var lambdaDelegate = (item, index) => index < list.Count - 1 && list[index + 1] == item;
list.Where(lambdaDelegate);
// without using lambdas as a shortcut:
var anonymousDelegate = delegate(item, index)
{
return index < list.Count - 1 && list[index + 1] == item;
}
list.Where(anonymousDelegate);
// and if we don't use anonymous methods (which is what lambdas represent):
function bool MyDelegate<TSource>(TSource item, int index)
{
return index < list.Count - 1 && list[index + 1] == item;
}
list.Where(MyDelegate);
The Where method has the following signature:
public static IEnumerable<TSource> Where<TSource>(this IEnumerable<TSource> source, Func<TSource, int, bool> predicate);
which is equivalent to:
delegate bool WhereDelegate<TSource>(TSource source, int index);
public static IEnumerable<TSource> Where<TSource>(this IEnumerable<TSource> source, WhereDelegate<TSource> predicate);
That's where the item and index are defined.
Behind the scenes, Where may do something like (just a guess, you can decompile to see):
public static IEnumerable<TSource> Where<TSource>(this IEnumerable<TSource> source, Func<TSource, int, bool> predicate)
{
int index = 0;
foreach (TSource item in source)
{
if (predicate(index, source))
yield return item;
index++;
}
}
So that's where index is initialized and gets passed to your delegate (anonymous, lambda, or otherwise).

Related

Need to understand the below code using func

I am new to delegates. Today I saw a code on this Link. AS i am new to c# and specially to delegates, i was unable to understand the below code.
public static void Main()
{
Func<String, int, bool> predicate = (str, index) => str.Length == index;
String[] words = { "orange", "apple", "Article", "elephant", "star", "and" };
IEnumerable<String> aWords = words.Where(predicate).Select(str => str);
foreach (String word in aWords)
Console.WriteLine(word);
}
The OutPut of the above code is "star". AS predicate is expecting to parameters but in this case we are not passing any parameters. Your comments will be really appreciated.
So first, there's a function definition:
Func<String, int, bool> predicate = (str, index) => str.Length == index;
which reads as "given a string represented as str and an index represented as index return true if the length of the string is equal to the index otherwise false"
When you come across to the enumerable pipeline:
IEnumerable<String> aWords = words.Where(predicate).Select(str => str);
you pass this function definition above, which is similar to:
words.Where((element, index) => element.Length == index).Select(str => str);
and as you can see only the element "star" meets that criteria, i.e. the "star" has length 4 and its index is also 4.
In regard to your confusion of:
AS predicate is expecting to parameters but in this case we are not
passing any parameters.
Note that when it comes to LINQ, we only specify the "what" and the "how" is an implementation detail. so in the aforementioned code, the Where clause will pass each element and its index to the predicate function.
On another note, the Select is superfluous, just IEnumerable<String> aWords = words.Where(predicate) should shuffice.
Let's start to examine this code from the first line.
Func<String, int, bool> predicate = (str, index) => str.Length == index;
Here we have simply the declaration of a variable named predicate This is a particular kind of variable whose value is a function that receives two parameters of type string and int and it is expected to return a bool. But where is the body of that function? Just after the equals sign. The (str,index) are the parameters and the body is simply a comparison between the length of the parameter str with the value of the parameter index.
=> str.Length == index returns true if the condition matches otherwise returns false
Now that we understand the declaration of the delegate, the next question is where we use it. This is even simpler. We can use it whenever we need a function that matches our delegate.
Now there is an overload of Where IEnumerable extension that expects just that, so we can simply put the predicate variable in that place and call the Where extension
In short, the code just says, "Select all words where the length equals index"
string[] words = { "orange", "apple", "Article", "elephant", "star", "and" };
// select all words where the length equals the index
var aWords = words.Where((str, i) => str.Length == i);
foreach (var word in aWords)
Console.WriteLine(word);
Where<TSource>(IEnumerable<TSource>, Func<TSource,Int32,Boolean>)
Filters a sequence of values based on a predicate. Each element's
index is used in the logic of the predicate function.
Func<T1,T2,TResult> Delegate
Encapsulates a method that has two parameters and returns a value of
the type specified by the TResult parameter.
So the only magic is the Func
Func<String, int, bool> predicate = (str, index) => str.Length == index;
Which (in this case) is just a fancy way of writing
public bool DoSomething(string str, int index)
{
return str.Length == index;
}
In essence its just a delegate, unlike an Action its capable of returning a value
Delegates (C# Programming Guide)
A delegate is a type that represents references to methods with a
particular parameter list and return type. When you instantiate a
delegate, you can associate its instance with any method with a
compatible signature and return type. You can invoke (or call) the
method through the delegate instance.
To simplify it a bit,
var aWords = words.Where(str => str.Length == 4);
is the same as:
Func<string, bool> predicate = str => str.Length == 4;
var aWords = words.Where(predicate);
predicate() executes it, and predicate without () can be used to pass it as parameter to a method.
With local functions (functions that can be declared inside other functions) introduced in C# 7, it can be :
bool predicate(string str) { return str.Length == 4; }
var aWords = words.Where(predicate);

C# Select Overload Method With Accumulator Not Working

I'd created a Map function in C# to act, in many ways, as it's JavaScript equivalent to project object types. I've since renamed these methods to 'Select' to use as overloads so they feel more 'integrated'. This is a chain, so bear with me, but the affected functions look like this...
public static TResult Project<TInput, TResult>(this TInput input, Func<TInput, TResult> projectionMapping)
=> projectionMapping(input);
public static TResult Project<TInput, TAccumulatedValue, TIncrementingValue, TResult>(this TInput input, Func<TInput, TAccumulatedValue, TResult> projectionMapping,
Func<TAccumulatedValue, TIncrementingValue, TAccumulatedValue> accumulator, TAccumulatedValue initialAccumulatorValue, TIncrementingValue increment)
=> projectionMapping(input, accumulator(initialAccumulatorValue, increment));
public static IEnumerable<TResult> Select<TInput, TAccumulatedValue, TIncrementingValue, TResult>(this IEnumerable<TInput> input,
Func<TInput, TAccumulatedValue, TResult> projectionMapping, Func<TAccumulatedValue, TIncrementingValue, TAccumulatedValue> accumulator,
TAccumulatedValue initialAccumulatorValue, TIncrementingValue increment)
=> input.Select(item => item.Project(projectionMapping, accumulator, initialAccumulatorValue, increment));
// This doesn't work.
public static IEnumerable<TResult> Select<TInput, TResult>(this IEnumerable<TInput> input,
Func<TInput, int, TResult> projectionMapping, int initialAccumulatorValue = -1, int increment = 1)
{
return input.Select(projectionMapping, (acc, inc) => acc + inc,
initialAccumulatorValue, increment);
}
I am using the int version of the map method, with the accumulator written into it, as follows...
MyList.Add(new List<MyObject>(rowValues.Map((val, headerNumber)
=> new MyObject(headerNumber, val), 0, 10)));
The problem is, that the value of headerNumber never changes (It's always 10) - The accumulator runs once and then is running for each Mapping but it's not remembering it's accumulation between runs. I feel I'm missing something glaringly obvious here but I can't see the wood for the trees.
If I input (for example) an array like this...
rowValues = new string[] { "Item 1", "Item 2", "Item 3" };
I would expect a list of MyObject items that contain the following data...
10 | "Item 1"
20 | "Item 2"
30 | "Item 3"
The problem is that you always call the accumulator with initialAccumulatorValue.
In order to achieve the goal, you need to maintain the accumulated value, and the easiest correct way to do that is using C# iterator method:
public static IEnumerable<TResult> Map<TInput, TAccumulatedValue, TIncrementingValue, TResult>(this IEnumerable<TInput> input,
Func<TInput, TAccumulatedValue, TResult> projectionMapping, Func<TAccumulatedValue, TIncrementingValue, TAccumulatedValue> accumulator,
TAccumulatedValue initialAccumulatorValue, TIncrementingValue increment)
{
var accumulatedValue = initialAccumulatorValue;
foreach (var item in input)
yield return projectionMapping(item, accumulatedValue = accumulator(accumulatedValue, increment));
}
Please note that the naïve attempt to use a combination of closure and Select
var accumulatedValue = initialAccumulatorValue;
return input.Select(item => projectionMapping(item, accumulatedValue = accumulator(accumulatedValue, increment)));
simply doesn't work because the accumulatedValue will be shared by the multiple executions of the returned select query, hence they will produce incorrect result. The iterator method has no such issue because the code is actually executed anytime the GetEnumerator() method is called.
I started by changing your 3rd function so that it just takes an accumulator function that returns the next index in the sequence. This allows the function to have state which you need to calculate the increasing accumulator values.
public static IEnumerable<TResult> Project<TInput, TAccumulatorValue, TResult>(this IEnumerable<TInput> input,
Func<TInput, TAccumulatorValue, TResult> projectionMapping,
Func<TAccumulatorValue> accumulator)
{
return input.Select(item => projectionMapping(item, accumulator()));
}
Then your function that takes the range arguments that didn't work can be written like this, which solves your problem.
public static IEnumerable<TResult> Project<TInput, TResult>(this IEnumerable<TInput> input,
Func<TInput, int, TResult> projectionMapping, int initialAccumulatorValue = 0, int increment = 1)
{
int curValue = initialAccumulatorValue;
return input.Project(projectionMapping,
() => { var ret = curValue; curValue += increment; return ret; });
}
Alternatively
Thinking about this problem in a different way you can make it more generic. All you are really doing is combining two sequences together using projectionMapping to combine the elements. In this case the second sequence happens to contain the accumulator values. Then to use this you just use the standard Linq function Zip, passing in the accumulator sequence and the projectionMapping function.
To get a linear sequence we can use Enumerable.Range, but to get a non-linear range we need to write a Range generator like this
public static IEnumerable<int> Range(int start, int increment)
{
for (; ; )
{
yield return start;
start += increment;
}
}
Examples
Showing both solutions in action
var items = new[] { "a", "b", "c" };
// use Project, returns: a10, b20, c30
var results = items.Project((s, i) => s + i.ToString(), 10, 10).ToList();
// use Zip with custom range, returns: a10, b20, c30
var results2 = items.Zip(Range(10, 10), (s, i) => s + i.ToString()).ToList();
// use Zip with standard range, returns: a1, b2, c3
var results3 = items.Zip(Enumerable.Range(1, int.MaxValue), (s, i) => s + i.ToString()).ToList();
Assuming the following
public class MyObject
{
public int Row { get; }
public string Value { get; }
public MyObject(int row, string value)
{
Value = value;
Row = row;
}
}
With the input source being:
var rows = new[] { "Item 1", "Item 2", "Item 3", "Item 4" };
Solution
To achieve the specific result given to the input you've presented, you can simply use the Select that is provided in the framework as such:
var result = rows.Select((v, i) => new MyObject((i+1)*10, v)).ToList();
Granted, that doesn't look very nice, but does the trick.
Ivan's answer is neater, but I'll persist the above in case someone finds it useful.

Explain Linq Microsoft Select - Indexed [Example]

I'm running throuth Microsoft's 101 LINQ Samples, and I'm stumped on how this query knows how to assign the correct int value to the correct int field:
public void Linq12()
{
int[] numbers = { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 };
var numsInPlace = numbers.Select((num, index) => new { Num = num, InPlace = (num == index) });
Console.WriteLine("Number: In-place?");
foreach (var n in numsInPlace)
{
Console.WriteLine("{0}: {1}", n.Num, n.InPlace);
}
}
I saw in SO #336758 that there have been errors in the examples before, but it is much more likely that I am just missing something.
Could someone explain this and how the compiler knows how to interpret this data correctly?
EDIT:
OK, I think my confusion comes from the LINQ extension that enables the Select feature to work. The Func and two int parameters IEnumerable<TResult> IEnumerable<int>.Select(Func<int,int,TResult> selector) are most likely the key to my lack of understanding.
I'm not really sure what you are asking of but the Select iterates over the list starting at index 0. If the value of the element at the current index is equal to the index it will set the InPlace property in the anonymous object to true. My guess is that the code above prints true for 3, 6 and 7, right?
It would also make it easier to explain if you write what you don't understand.
Jon Skeet has written a series of blog post where he implement linq, read about Select here: Reimplementation of Select
UPDATE: I noticed in one of your comment to one of the other comments and it seems like it is the lambda and not linq itself that is confusing you. If you read Skeet's blog post you see that Select has two overloads:
public static IEnumerable<TResult> Select<TSource, TResult>(
this IEnumerable<TSource> source,
Func<TSource, TResult> selector)
public static IEnumerable<TResult> Select<TSource, TResult>(
this IEnumerable<TSource> source,
Func<TSource, int, TResult> selector)
The Select with index matches the second overload. As you can see it is an extension of IEnumerable<TSource> which in your case is the list of ints and therefor you are calling the Select on an IEnumerable<int> and the signature of Select becomes: Select<int, TResult>(this IEnumerable<int> source, Func<int, int, TResult> selector). As you can see I changed TSource against int, since that is the generic type of your IEnumerable<int>. I still have TResult since you are using anonymous type. So that might explain some parts?
Looks correct to me.
First you have an anonymous type with Num and InPlace being created. Then the LINQ Select is just iterating over the elements with the element and the index of that element. If you were to rewrite it without linq and anonymous classes, it would look like this:
class NumsInPlace
{
public int Num { get; set; }
public bool InPlace { get; set; }
}
int[] numbers = { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 };
List<NumsInPlace> numsInPlace = new List<int>();
for (int index = 0; i < numbers.length; i++)
{
int num = numers[index];
numsInPlace.Add(new NumsInPlace() { Num = num, InPlace = (index == num) });
}
Console.WriteLine("Number: In-place?");
foreach (var n in numsInPlace)
{
Console.WriteLine("{0}: {1}", n.Num, n.InPlace);
}
The MSDN on Enumerable.Select has the details, but the projection function (num, index) always has the item first, then the index second (if supplied).
how does the compiler know that LINQ Select is using the index value as an index to the array?
The compiler doesn't know about index values. The implementation of that overload of Select knows about index values.
//all the compiler sees is a method that accepts 2 int parameters and returns a bool.
Func<int, int, bool> twoIntFunc = (x, y) => (x == y);
//The compiler sees there's an overload of Enumerable.Select which accepts such a method.
IEnumerable<bool> query = numbers.Select(twoIntFunc);
Enumerable.Select's implementation does the rest of the work by calling that method with the appropriate parameters.
The first argument to selector represents the element to process. The second argument to selector represents the zero-based index of that element in the source sequence.
So - Select will call your method with (5, 0) first, then Select calls it with (4, 1).
The lambda expression (num, index) => new { Num = num, InPlace = (num == index) } is executed once for each element in the input sequence and passed the item and it's index as the arguments.
Update
Lambda expressions can be implicitly typed, that is, from the required type, the compiler can figure out (or imply) what types you intend the arguments to be.
(num, index) => new { Num = num, InPlace = (num == index) }
is equivalent to
someAnonymousType MyMethod(int num, int index)
{
return new
{
Num = num,
InPlace = (num == index)
};
}
obviously you can't write the latter because you can't type the name of an anonymous type, but the compiler can ;)
The compiler knows this because the overload of Select that you're using accepts a Func<TSource, Int32, TResult>, this is a Func that takes, two arguments of type TSource (the type of your IEnumberable<T>, in this case int) and an Int32 (which represents the index) and returns an object of TResult, being whatever you choose to return from your function, in this case, an anonymous type.
The lambda can be cast to the required type and therefore it just works.
The second argument in the select is the index, which increments as the compiler traverses the array of numbers. The compiler will see
num index num = index
5 0 false
4 1 false
1 2 false
3 3 true
9 4 false
8 5 false
6 6 true
7 7 true
2 8 false
0 9 false
It provides true for 3,6 and 7. You need to remember it starts with the index at 0.

How is a variable in a lambda expression given its value

How does index in the below example obtain its value? I understand that n is automatically obtained from the source numbers, but, while the meaning is clear, I do not see how index is given its value:
int[] numbers = { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 };
var firstSmallNumbers = numbers.TakeWhile((n, index) => n >= index);
The signature of TakeWhile is:
public static IEnumerable<TSource> TakeWhile<TSource>(this IEnumerable<TSource> source, Func<TSource, int, bool> predicate);
This version of TakeWhile supplies the index of the source element in the sequence as the second parameter to the predicate. I.e. the predicate is called as predicate(5, 0), then predicate(4, 1), predicate(1, 2), predicate(3, 3) etc. See the MSDN documentation.
There is also a “simpler” version of the function, supplying only the values in the sequence, see MSDN.
The index is generated by the implementation of TakeWhile, which might look a bit like this.
Things become clear as long as you figure out how TakeWhile can be implemented :
public static IEnumerable<TSource> TakeWhile<TSource>(this IEnumerable<TSource> source, Func<TSource, int, bool> predicate)
{
int index = 0;
foreach (TSource item in source)
{
if (predicate(item, index))
{
yield return item;
}
else
{
yield break;
}
index++;
}
}

Method signature for IList<T>.Split() extension method

I'd like to be able to write the following code:
// contains 500 entries
IList<string> longListOfStrings = ...
// shorterListsOfStrings is now an array of 5 IList<string>,
// with each element containing 100 strings
IList<string>[] shorterListsOfStrings = longListOfStrings.Split(5);
To do this I have to create a generic extension method called Split that looks something like the following:
public static TList[] Split<TList>(this TList source, int elementCount)
where TList : IList<>, ICollection<>, IEnumerable<>, IList, ICollection, IEnumerable
{
return null;
}
But when I try to compile that, the compiler tells me that IList<>, ICollection<> and IEnumerable<> require a type argument. So, I changed the definition to the following:
public static TList<TType>[] Split<TList<TType>>(this TList<TType> source, int elementCount)
where TList : IList<TType>, ICollection<TType>, IEnumerable<TType>, IList, ICollection, IEnumerable
{
return null;
}
but then the compiler complains that it can't find type TList. I have an idea that I'm overcomplicating things but I can't see how... any help is appreciated!
Yes, I think you're overcomplicating things. Try this:
public static IList<T>[] Split<T>(this IList<T> source, int elementCount)
{
// What the heck, it's easy to implement...
IList<T>[] ret = new IList<T>[(source.Count + elementCount - 1)
/ elementCount];
for (int i = 0; i < ret.Length; i++)
{
int start = i * elementCount;
int size = Math.Min(elementCount, source.Count - i * start);
T[] tmp = new T[size];
// Would like CopyTo with a count, but never mind
for (int j = 0; i < size; j++)
{
tmp[j] = source[j + start];
}
ret[i] = tmp;
}
return ret;
}
After all, you're not going to change which kind of list you create within the method based on the source, are you? You'll presumably create a List<T> (or maybe a T[]) even if I pass in some other implementation.
You might want to look at the Batch method in MoreLINQ for an IEnumerable<T>-based implementation.
How about this:
public static IList<TResult>[] Split<TSource, TResult>(
this IList<TSource> source, // input IList to split
Func<TSource, TResult> selector, // projection to apply to each item
int elementCount // number of items per IList
) {
// do something
}
And if you don't need a version to project each item:
public static IList<T>[] Split<T>(
this IList<T> source, // input IList to split
int elementCount // number of items per IList
) {
return Split<T, T>(source, x => x, elementCount);
}

Categories

Resources