Func<> delegate - Clarification - c#

When an array is given:
int[] a={1,3,4,5,67,8,899,56,12,33}
and if i wish to return the even numbers using LINQ
var q=a.where(p=>p%2==0)
If i were to use C#2.0 and strictly func<> delegate what is the way to solve it?
I tried :
Func<int, bool> func = delegate(int val) { return val % 2 == 0; };
but I am confused how to link the array "a" here.

int[] q = Array.FindAll<int>(a, delegate(int p) { return p % 2 == 0; });
(note this uses Predicate<int>, which is the same signature as Func<int,bool>)

You can use Predicate and Array.FindAll.
Predicate<int> func = delegate(int val) { return val % 2 == 0; };
Array.FindAll<int>(a, func);

Related

How to use ?? with lambda expression?

Can we simplify the following with ?? and lambda expression?
Func<int, int> func = f; // f is a function parameter
if (func == null) // if f passed by the user is null then we use the default identity function f(x)=x.
func = x => x;
I cannot do something Func<int, int> func = f ?? x=>x;. Could you?
Edit
My scenario is as follows.
class Program
{
static double Average(int[] data, Func<int, int> f = null)
{
int sum = 0;
Func<int, int> func = f ?? new Func<int, int>(x => x);
//Func<int, int> func = f;
//if (func == null)
// func = x => x;
foreach (int x in data)
sum += func(x);
return (double)sum / data.Length;
}
static void Main(string[] args)
{
int[] data = { 1, 2, 3 };
Console.WriteLine(Average(data));
}
}
The precedence of null-coalescing operator is higher than lambda declaration.
Func<int, int> func = f ?? (x => x);
Possible duplicate of Null-coalescing operator and lambda expression
This should work
Func<int, int> func = f ?? (x=>x);
Your statement is parsed as
Func<int, int> func = (f ?? x)=>x;
Please search through the available answers first to check if somebody has already answered it.

Join 2 lists have different length by in LINQ

How can I join 2 lists of different lengths. it should join with the sequence.
Eg.
{1,2,3,4} with {5,6,7}
I need to get result like below.
{{1,5}, {2,6}, {3,7}, {4,null}}
I tried this.
var qry = a.Select((i, index) => new {i, j = b[index]});
But its throwing error since the lists are having different lengths.
Please help me to get the solution.
This should work:
var a = new int?[] { 1, 2, 3, 4 };
var b = new int?[] { 5, 6, 7 };
var result = Enumerable.Range(0, Math.Max(a.Count(), b.Count()))
.Select(n => new[] {a.ElementAtOrDefault(n), b.ElementAtOrDefault(n)});
Do note the ? in the array declarations. That is necessary in order to have null values in the resulting list. Omitting the ? causes the result to have 0 instead of null.
If you can't or don't want to declare the arrays as int?, then you'll have to do the cast in the Select like so:
var result = Enumerable.Range(0, Math.Max(a.Count(), b.Count()))
.Select(n => new[] { a.Select(i => (int?)i).ElementAtOrDefault(n), b.Select(i => (int?)i).ElementAtOrDefault(n) });
This second bit of code will work correctly with regular int arrays or Lists.
The ugly but working version is the following:
a.Cast<int?>().Concat(Enumerable.Repeat<int?>(null, Math.Max(b.Count() - a.Count(), 0)))
.Zip(b.Cast<int?>()
.Concat(Enumerable.Repeat<int?>(null, Math.Max(a.Count() - b.Count(), 0))),
(x, y) => new { x, y });
Its drawback it double evaluation of a collection (the first one is by calling .Count()).
So it is better just to write an extension
static IEnumerable<TResult> ZipNull<T1, T2, TResult>(this IEnumerable<T1> a, IEnumerable<T2> b, Func<T1?, T2?, TResult> func)
where T1 : struct
where T2 : struct
{
using (var it1 = a.GetEnumerator())
using (var it2 = b.GetEnumerator())
{
while (true)
{
if (it1.MoveNext())
{
if (it2.MoveNext())
{
yield return func(it1.Current, it2.Current);
}
else
{
yield return func(it1.Current, null);
}
}
else
{
if (it2.MoveNext())
{
yield return func(null, it2.Current);
}
else
{
break;
}
}
}
}
}
and use it as
a.ZipNull(b, (x, y) => new { x, y });
What you have is effectively a Zip, but where it zips to the end of the longer, rather than the shorter, of the two sequences. You can write such a Zip method, with something that looks a bit similar to the actual Zip implementation:
public static IEnumerable<TResult> ZipAll<TSource, TSecond, TResult>(this IEnumerable<TSource> source,
IEnumerable<TSecond> other,
Func<TSource, TSecond, TResult> projection)
{
using (var firstIterator = source.GetEnumerator())
using (var secondIterator = other.GetEnumerator())
{
while (true)
{
bool hasFirst = firstIterator.MoveNext();
bool hasSecond = secondIterator.MoveNext();
TSource first = hasFirst ? firstIterator.Current : default(TSource);
TSecond second = hasSecond ? secondIterator.Current : default(TSecond);
if (hasFirst || hasSecond)
yield return projection(first, second);
else
yield break;
}
}
}
With that you can write:
a.ZipAll(b, (i, j) => new { i, j });
You could make the code a bit shorter by requiring the inputs to be lists, but the code wouldn't be any faster as lists, just less typing, and it's not like it's that much extra work to support any sequence, so I'd say it's worth the added few lines of code.
Simply loop through the lists and construct new, let's say Dictionary<int?, int?> out of each list element:
var theFirstList = new List<int?> { 1, 2, 3, 4 };
var theSecondList = new List<int?> { 5, 6, 7 };
var el = new Dictionary<int?, int?>();
var length = Math.Max(theFirstList.Count, theSecondList.Count);
for (int i = 0; i < length; i++)
{
el.Add(theFirstList.ElementAtOrDefault(i), theSecondList.ElementAtOrDefault(i));
}
var x = new[] { 1, 2, 3, 4 }.ToList();
var y = new[] { 5, 6, 7 }.ToList();
var arrayLists = new[] {x, y}.OrderBy(t => t.Count).ToList();
var result = arrayLists
.Last()
.Select((item, i) => new[] { x[i], i < arrayLists.First().Count ? y[i] : (int?)null })
.ToList();
this should work for any IEnumerable

Convert a string in a List<int> using LINQ (cleaner way)

I have this string:
string input = "1,2,3,4,s,6";
Pay attention to the s character.
I just want to convert this string in a List<int> using LINQ. I initially tried in this way:
var myList = new List<int>();
input.Split(',').ToList().ForEach(n =>
myList.Add(int.TryParse(n, out int num) ? num : -1)
);
lista.RemoveAll(e => e == -1);
But I prefer not have any -1 instead of a no-number characters.
So now I try with this:
var myList = new List<int>();
input.Split(',').ToList()
.FindAll(n => int.TryParse(n, out int _))
.ForEach(num => myList.Add(int.Parse(num)));
I prefer this, but is really a shame that the parsing happening two times (TryParse at first and then Parse). But, from what I understand, the out variable in TryParse is useless (or not?).
Have you others suggests (using LINQ)?
public class ParsesStringsToIntsWithLinq
{
public IEnumerable<int> Parse(string input)
{
var i = 0;
return (from segment in input.Split(',')
where int.TryParse(segment, out i)
select i);
}
}
[TestClass]
public class Tests
{
[TestMethod]
public void IgnoresNonIntegers()
{
var input = "1,2,3,4,s,6";
var output = new ParsesStringsToIntsWithLinq().Parse(input);
Assert.IsTrue(output.SequenceEqual(new []{1,2,3,4,6}));
}
}
It doesn't return a List<int> but I have to draw the line somewhere. You can make a list out of it.
Using a nice extension method
public static IEnumerable<T> AsSingleton<T>(this T source) {
yield return source;
}
(which you can replace with new[] { n } if preferred)
input.Split(',').SelectMany(s => Int32.TryParse(s, out var n) ? n.AsSingleton() : Enumerable.Empty<int>()).ToList()
I prefer to make a nice helper function:
Func<string, int?> tryParse = s => int.TryParse(s, out int n) ? (int?)n : null;
Then it's a simple matter to parse:
string input = "1,2,3,4,s,6";
List<int> myList =
input
.Split(',')
.Select(s => tryParse(s))
.Where(n => n.HasValue)
.Select(n => n.Value)
.ToList();
That gives:
1
2
3
4
6
int i = 0;
var myList = (from s in input.Split(',') where int.TryParse(s, out i) select i).ToList();
If the numbers are always single ASCII digits:
var myList = "1,2,3,4,s,6".Select(c => c ^ 48).Where(i => i < 10).ToList();
Few slower RegEx alternatives for fun:
var myList2 = Regex.Split("1,2,3,4,s,6", "[^0-9]+").Select(int.Parse).ToList(); // if the string starts and ends with digits
var myList3 = Regex.Replace("1,2,3,4,s,6", "[^0-9]+", " ").Trim().Split(' ').Select(int.Parse).ToList();
var myList4 = Regex.Matches("1,2,3,4,s,6", "[0-9]+").Cast<Match>().Select(m => int.Parse(m.Value)).ToList();
Why does it have to be LINQ?
Try:
//Come up a better name...
public static List<int> ConvertToIntListNoLinq(string input)
{
List<int> output = new List<int>();
foreach(string s in input.Split(','))
{
if(int.TryParse(s, out int result))
{
output.Add(result);
}
}
return output;
}
Fiddle
Here's a generic LINQ extension, which utilizes a delegate. This will allow you to pass in a function returning a bool, while "retaining" the result of the out variable (like int.TryParse).
Usage:
string input = "1,2,3,4,s,6";
List<int> myList = input.Split(',').SelectTry<string, int>(int.TryParse).ToList();
Code:
using System.Collections.Generic;
public static class LINQExtensions
{
public delegate bool TryFunc<TSource, TResult>(TSource source, out TResult result);
public static IEnumerable<TResult> SelectTry<TSource, TResult>(
this IEnumerable<TSource> source, TryFunc<TSource, TResult> selector)
{
foreach (TSource item in source)
{
TResult result;
if (selector(item, out result))
{
yield return result;
}
}
}
}
I think this is a clean way too. Even though it uses that extra variable, the benefit we get is it is clean and understandable.
string ids = "2,4,2,4,5,s"
const int inValidInt = -99;
var ids = ids.Split(',')
.Select(id =>
{
int parsedId = int.TryParse(id, out parsedId) ? parsedId : inValidInt;
return parsedId;
})
.Where(x => x != inValidInt).ToList();
You can do it like this:
List<int> numbers = input
.Split(',')
.Where(t => int.TryParse(t, out int a))
.Select(int.Parse)
.ToList();
You don't need to call .Split(...).ToList() as String[] is already enumerable.
You can use multiple statements in a lambda with braces.
The FindAll, ForEach and RemoveAll methods are not Linq methods, they're members of List<T>. Their Linq equivalent is Where.
Like so:
List<Int32> numbers = "1,2,3,4,s,6"
.Split(',')
.Select( s => { Int32 val; return Int32.TryParse( s, NumberStyles.Integer, CultureInfo.InvariantCulture, out val ) ? val : -1 } )
.Where( n => n != -1 )
.ToList();
You can make it more concise with a helper method:
static Int32 Parse(String s) {
Int32 ret;
if( Int32.TryParse( s, NumberStyles.Integer, CultureInfo.InvariantCulture, out ret ) ) {
return ret;
}
return -1;
}
Becomes:
List<Int32> numbers = "1,2,3,4,s,6"
.Split(',')
.Select( s => Parse( s ) )
.Where( n => n != -1 )
.ToList();
If you don't want to reserve -1 then you can use nullable ints:
static Int32? Parse(String s) {
Int32 ret;
if( Int32.TryParse( s, NumberStyles.Integer, CultureInfo.InvariantCulture, out ret ) ) {
return ret;
}
return null;
}
List<Int32> numbers = "1,2,3,4,s,6"
.Split(',') // String to String[]
.Select( s => Parse( s ) ) // String[] to IEnumerable<Int32?>
.Where( n => n != null ) // filter out nulls
.Select( n => n.Value ) // IEnumerable<Int32?> to IEnumerable<Int32>
.ToList(); // IEnumerable<Int32> to List<Int32>

How to create a For_Each_With_Condition_With_Index Extension method (EM)

I have a ForEachWithIndex EM
static void ForEachWithIndex<T>(this IEnumerable<T> enu, Action<T, int> action)
{
int i = 0;
foreach(T item in enu)
action(item, i++);
}
I call it like this
my_int_array.ForEachWithIndex((x, i) => x += i);
Now i want to create one which checks for condition and then perform that action.
Usually i use above as
my_int_array.ForEachWithIndex((x,i) =>
{
if (x != 0)
x += i;
});
I want a EM that takes that condition as parameter also. How to do that?
I would try to avoid building one big extension method which does it all. Break it out, just like LINQ does.
Personally I wouldn't actually do any of this though - I'd build a query with LINQ, then use a foreach statement for the action:
// Assuming you want the *original* indexes
var query = array.Select((Value, Index) => new { value, Index })
.Where(pair => pair.Index != 0);
foreach (var pair in query)
{
// Do something
}
It's hard to know exactly what you're trying to do, given that incrementing the lambda parameter won't really achieve anything. I would strongly encourage you to think of composing blocks though... and you may find Eric Lippert's views on foreach vs ForEach interesting.
Just add the condition delegate to parameters list:
static void ForEachWithIndexWithCondition<T>(this IEnumerable<T> enu,
Func<T, int, bool> condition, Action<T, int> action)
{
int i = 0;
foreach (T item in enu)
{
if (condition(item, i))
action(item, i);
i++;
}
}
Usage:
var list = new List<string> { "Jonh", "Mary", "Alice", "Peter" };
list.ForEachWithIndexWithCondition(
(s, i) => i % 2 == 0,
(s, i) => Console.WriteLine(s));
You need to pass an additional Func parameter, something like this:
public static void ForEachWithIndex<T>(this IEnumerable<T> enu,
Action<T, int> action, Func<T, int, bool> condition)
{
int i = 0;
foreach (T item in enu)
{
if (condition(item, i))
{
action(item, i);
}
++i;
}
}
And this is what the code for your example look like:
my_int_array.ForEachWithIndex((x, i) => x += i, (x, i) => x != 0);

Is there any way to pass the lambda expression as a variable or argument?

I need to pass the lambda query as a parameter, the followings code is sample and I am interesting to find an implement for it, there is samples: some thing like this:
var expr1 = Where(n => n > 6).OrderBy(n => n % 2 == 0).Select(n => n);
var expr2 = TakeWhile((n, index) => n >= index));
And Use it Like this:
public void UseLambda<T> (IEnumerable<T> source , lambda Expr){
var items= Expr.Compile(source);
foreach(var item in items)
Console.Writeline(item.ToString());
}
public void Main(){
List<int> numbers = new List<int> { 10, 24, 9, 87, 193, 12, 7, 2, -45, -2, 9 };
var expr1 = Where(n => n > 6).OrderBy(n => n % 2 == 0).Select(n => n);
UseLambda(numbers, expr1);
}
Does any one have an idea about it?
Check Func(Of T, TResult) Delegate (MSDN)
using System;
public class LambdaExpression
{
public static void Main()
{
Func<string, string> convert = s => s.ToUpper();
string name = "Dakota";
Console.WriteLine(convert(name));
}
}
From MSDN
The underlying type of a lambda expression is one of the generic Func delegates. This makes it possible to pass a lambda expression as a parameter without explicitly assigning it to a delegate. In particular, because many methods of types in the System.Linq namespace have Func(Of T, TResult) parameters, you can pass these methods a lambda expression without explicitly instantiating a Func(Of T, TResult) delegate.
EDIT
Possible solution for your case
static void Main(string[] args)
{
List<int> numbers = new List<int> { 10, 24, 9, 87, 193, 12, 7, 2, -45, -2, 9 };
Func<IEnumerable<int>, IEnumerable<int>> expr = n => n.Where(n1 => n1 > 6).OrderBy(n1 => n1 % 2 == 0).Select(n1 => n1);
UseLambda<int>(numbers, expr);
}
private static void UseLambda<T>(List<T> numbers,
Func<IEnumerable<T>,
IEnumerable<T>> expr)
{
var values = expr(numbers);
foreach (var item in values) {
Console.WriteLine(item);
}
}
If you define your LINQ expressions like this:
Func<IEnumerable<int>, IEnumerable<int>> expr1 =
l => l.Where(n => n > 6).OrderBy(n => n % 2 == 0).Select(n => n);
Func<IEnumerable<int>, IEnumerable<int>> expr2 =
l => l.TakeWhile((n, index) => n >= index);
And your UseLambda method as:
public void UseLambda<T> (IEnumerable<T> source
,Func<IEnumerable<T>, IEnumerable<T>> lambda)
{
var items= lambda(source);
foreach(var item in items)
Console.Writeline(item.ToString());
}
}
Then you I think you have what you're looking for.
Do you mean something like this:
public void UseLambda<T> (IEnumerable<T> source , Func<T, bool> where, Func<T, bool> order)
{
if(source != null)
{
IOrderedEnumerable<T> orderBy = source.Where(where).OrderBy(order);
foreach (T value in orderBy)
{
Console.WriteLine(value);
}
}
}
So that you could call it like so:
UseLambda(numbers, x => x > 6, x => x % 2 == 0);
Well, a lambda is nothing but a delegate, so you could have a method like this:
public void DoIt(IEnumerable a, Action<IEnumerable> performThis)
{
performThis(a);
}
But where's the sense in it? Instead of calling a method that applies your lambda, why not calling it directly as you do in the last lines of your code?
public void UseLambda<T>(IEnumerable<T> source, Expression<Func<IEnumerable<T>, IEnumerable<T>>> expr)
{
var items = expr.Compile();
foreach (var item in items.Invoke(source))
{
Console.WriteLine(item.ToString());
}
}
public void Main()
{
Expression<Func<IEnumerable<int>, IEnumerable<int>>> expr = s => s.Where(n => n > 6).OrderBy(n => n % 2 == 0).Select(n => n);
var list = new List<int> { 10, 24, 9, 87, 193, 12, 7, 2, -45, -2, 9 };
UseLambda(list, expr);
}

Categories

Resources