Pass LINQ query to method to select dynamically form collection - c#

I already looked up on the question on SO, but couldn't find a solution for my problem.
In my program is a class whose sole reason is selecting from a collection of data passed to it via constructor.
What I need to to is pass a LINQ query to the selecting method to select from said data. However I have no luck solving my problem.
Here is the code:
public class ServiceClient<TInput>
{
private readonly IEnumerable<TInput> data;
public ServiceClient(IEnumerable<TInput> dataInput)
{
this.data = dataInput;
}
public TResult Send<TResult>(Func<IEnumerable<TInput>, TResult> selector)
{
var selectedData = this.data.Select(selector); // How to do the selection here???
// ...
}
}
The class is called this way:
private static void Main(string[] args)
{
var persons = new List<Person>
{
new Person { Id = 0, FamilyId = 0 },
new Person { Id = 1, FamilyId = 0 },
new Person { Id = 2, FamilyId = 1 }
};
var func = new Func<IEnumerable<Person>, Person>(Target);
var client = new ServiceClient<Person>(persons);
client.Send(func);
}
private static Person Target(IEnumerable<Person> enumerable)
{
return enumerable.SingleOrDefault(p => p.Id == 0);
}

Replace:
var selectedData = this.data.Select(selector);
with:
var selectedData = selector(this.data);
It should be enough.
selector is delegate that acceps collection and returns single element, so you need invoke selector delegate with data argument.
If you would like to use Select like this.data.Select(..) your selector delegate should rather be like Func<TInput, TResult> - delegate that projects one element into another.

You need to change Send that way:
public TResult Send<TResult>(Func<IEnumerable<TInput>, TResult> selector)
{
return selector(data);
}

Related

pass lambda expression as callback to an extension method and pass parameter to it

I am trying to understand the concept of lambda expression,extension method,Linq and IEnumerable interface. You can guess that i am farely new to c sharp.Here i've come up with a problem which will incorporate all the above mentioned concepts . Here i have a list which contain three object.I want to change the name property of a Students object in a specified index .I wrote an extension method which accept a callback function.Callback function accepts an integer index and a new Name string. It should change the name property and return the object .But my code failed to do so as i am not sure how to pass parameter to Func callback in extension method.I am in need of some assistant to understand the problem and fix errors from my code ?
class Program
{
static void Main(string[] args)
{
List<Students> students = new List<Students>();
students.Add(new Students(111443, "sakib"));
students.Add(new Students(111445, "zami"));
students.Add(new Students(111444, "habib"));
var student = students.First();
var changed1 = students.Change((int num,string newname) => { return students[num].s_name = newname;});
}
}
public class Students
{
public int s_id;
public string s_name;
public Students(int id, string name)
{
this.s_id = id;
this.s_name = name;
}
}
public static class LinqHelper
{
public static IEnumerable<T> Change<T> (this IEnumerable<T> source, Func<int,string,T> callback)
{
var myList = new List<Students>();
myList.Add(callback(1,"zami")); // i was passing parameter here which is not so helpful i guess !
return myList;
}
}
The Func < int, string, T > denotes a function that accepts an integer and string as inputs and T as the return type. The anonymous function you have used has a return type of "string":
var changed1 = students.Change((int num,string newname) => { return students[num].s_name = newname;});
You should return the student instance from the function to make it work. Try replacing the above code with the following:
var changed1 = students.Change((int index, string newname) =>
{
var studentObj = students[index];
studentObj.s_name = newname;
return studentObj;
});
To allow the LinqHelper to accept the index and argument, use the following:
public static class LinqHelper
{
public static IEnumerable<T> Change<T>(this IEnumerable<T> source, Func<int, string, T> callback, int index, string argument)
{
var myList = new List<T>();
myList.Add(callback(index, argument)); // i was passing parameter here which is not so helpful i guess !
return myList;
}
}
And then, you could invoke the method as follows:
var changed1 = students.Change((int index, string newname) =>
{
var studentObj = students[index];
studentObj.s_name = newname;
return studentObj;
},
1,
"zami");
You haven't created the lambda that evaluated to Func<int, string, T>. Your call to Change extension should look like:
var changed1 = students.Change((num, newnam) => {
students[num].s_name = newnam;
return students[num];
});
(you should return T as Func requires).

Filtering IEnumerable by collection (Linq)

I want to filter an IEnumerable object by a specific property of whatever object it is collecting. I want the option to filter by one or more property value but how many values (and what values) to filter by is only known at runtime.
Ok, so to give an example, the collected objects could be the following struct:
public struct Person
{
public string Name { get; set; }
public string Profession{ get; set; }
}
This struct could then be used by the following list, which I have populated with some arbitrary values:
List<Person> people= new List<Person>;
people.Add(new Person(){Name = "Mickey", Profession="Tinker"};
people.Add(new Person(){Name = "Donald", Profession="Tailor"};
people.Add(new Person(){Name = "Goofy", Profession="Soldier"};
people.Add(new Person(){Name = "Pluto", Profession="Spy"};
This is then put into an IEnumerable (all of them are transferred to it first)
var wantedPeople = from n in this.people select n;
So say a user was only interested in the "Tailor" and "Spy" professions, and via some sort of gui trickery the following collection was created:
List<string> wantedProfessions = new List<string>();
wantedProfessions.Add("Tailor");
wantedProfessions.Add("Spy");
Now what Linq statement can I use to filer my wantedPeople so it only includes the tailor and spy entries?
I know I could use a where clause but I don't know how to tailor it to get what I want (and doing the following is not what I want as it only works with the wantedProfessions collection above (e.g. this collection will change at runtime):
wantedPeople = from n in wantedPeople
where n.Profession == wantedProffessions[0] || n.Profession == wantedProffessions[1]
select n;
If you want to check any wanted profession from given list:
wantedPeople = from n in wantedPeople
where wantedProffessions.Contains(n.Profession)
select n;
Or you can build query with lambda syntax by applying filters one by one:
var query = people.AsEnumerable();
if (!String.IsNullOrEmpty(name))
query = query.Where(p => p.Name == name);
if (wantedProfessions.Any())
query = query.Where(p => wantedProfessions.Contains(p.Profession));
If you wanted to create more complex filters, like some name, and several professions, you can use Specification pattern. Specification can be defined by this simple interface:
public interface ISpecification<T>
{
bool Satisfied(T entity);
}
It just checks whether given entity (person) satisfies specification. Specification also look very simple:
public class PersonNameSpecification : ISpecification<Person>
{
private string _name;
public PersonNameSpecification(string name)
{
_name = name;
}
public bool Satisfied(Person person)
{
return person.Name == _name;
}
}
Profession specification:
public class PersonProfessionSpecification : ISpecification<Person>
{
private string[] _professions;
public PersonProfessionSpecification(params string[] professions)
{
_professions = professions;
}
public bool Satisfied(Person person)
{
return _professions.Contains(person.Profession);
}
}
You can create specifications which implement boolean logic, like OrSpecification or AndSpecification:
public class AndSpecification<T> : ISpecification<T>
{
private ISpecification<T> _specA;
private ISpecification<T> _specB;
public AndSpecification(ISpecification<T> specA, ISpecification<T> specB)
{
_specA = specA;
_specB = specB;
}
public bool Satisfied(T entity)
{
return _specA.Satisfied(entity) && _specB.Satisfied(entity);
}
}
public static class SpecificationExtensions
{
public static ISpecification<T> And<T>(
this ISpecification<T> specA, ISpecification<T> specB)
{
return new AndSpecification<T>(specA, specB);
}
}
Now you can create complex specification which describes people you want to get:
var professionSpec = new PersonProfessionSpecification("Tailor", "Spy");
var nameSpec = new PersonNameSpecification("Pluto");
var spec = professionSpec.And(nameSpec);
And get required people:
var result = people.Where(spec.Satisfied);
Sergey B's Solution is the correct one for your example.
Assuming that you weren't using a collection that had the Contains() method, you could also do the following:
var wantedPeople = from n in people
from p in wantedProffessions
where n.Profession.Equals(p)
select n;

Generic method to set the value of a property using expressions/lambda

I am trying to find a generic way to assign values to a property dictated by a lambda expression, look at the example code below, how would the signature for the ConverToEntities method look and how would it be called?
static void Main()
{
List<long> ids = new List<long> {1, 2, 3};
//Non generic way
List<Data> dataItems = ids.ConvertToDataItems();
//Generic attempt!!
List<Data> differntDataItems =
ids.ConvertToEntities<Data>( p => p.DataId );
}
public class Data
{
public long DataId;
public string Name;
}
public static class ExtensionMethods
{
public static List<Data> ConvertToDataItems(this List<long> dataIds)
{
return dataIds.Select(p => new Data { DataId = p }).ToList();
}
public static List<T> ConvertToEntities<TProp>(
this List<long> entities, Func<TProp> lambdaProperty )
{
return entities.Select(p => new T {lambdaProperty} ).ToList();
}
}
Ok. The closest I could get was this :
class Program
{
static void Main(string[] args)
{
List<long> ids = new List<long> { 1, 2, 3 };
//Non generic way
List<Data> dataItems = ids.ConvertToDataItems();
//Generic attempt!!
Func<long, Data> selector = (p => new Data { DataId = p });
List<Data> differntDataItems = ids.ConvertToEntities<Data>(selector);
}
}
public class Data
{
public long DataId;
public string Name;
}
public static class ExtensionMethods
{
public static List<Data> ConvertToDataItems(this List<long> dataIds)
{
return dataIds.Select(p => new Data { DataId = p }).ToList();
}
public static List<TProp> ConvertToEntities<TProp>(this List<long> entities, Func<long, TProp> selector)
{
return entities.Select(selector).ToList();
}
}
This works.
I have the feeling you got urself a little confused with what you actually want as the return type. It would be cool to be able to specify what we want in the method call or smth. For example:
public static List<TProp> ConvertToEntities<T, TProp>(List<T> entities, Func<T, TProp> selector)
{
return entities.Select(selector).ToList();
}
This provides us more flexibility on the return type. But since we are doing this using extensions, I assume this is impractical because we need to know what type we are extending:
this List<long> entities,
Nice question.
EDIT Code suggestion fix.
You can do something like this, but it's not as simple or nice. The lambda p => p.DataId gives you the get accessor of the property. You could use Expressions to get the setter, but it's probably better to use the setter directly in the lambda:
List<Data> differntDataItems =
ids.ConvertToEntities<long, Data>((p, i) => p.DataId = i);
The implementation would look like this:
public static List<T> ConvertToEntities<TProp, T>(
this List<TProp> dataIds, Action<T, TProp> lambdaProperty)
where T : new()
{
return dataIds.Select(
p =>
{
var result = new T();
lambdaProperty(result, p);
return result;
}).ToList();
}
I believe #Zortkun is right about the return type. Try the followin:
public static List<TProp> ConvertToEntities<TProp>(
this List<long> entities, Func<long, TProp> lambdaProperty )
{
return entities.Select(lambdaProperty).ToList();
}
and you would call it as follows:
ids.ConvertToEntities<Data>( p => new Data { DataId = p } );

Generic method to compare/filter two lists using expressions/lambda

I want to compare two lists, based on a filter expression; not sure how to construct the lambda expression for the generic method; Please refer to the code below; or is there an easier way via an intersect in LINQ?
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
Data d1 = new Data {Id = 1, Name = "One"};
Data d2 = new Data { Id = 2, Name = "Two" };
Data d3 = new Data { Id = 3, Name = "Three" };
Data d4 = new Data { Id = 1, Name = "One" };
Data d5 = new Data { Id = 2, Name = "Two" };
Data d6 = new Data { Id = 4, Name = "Four" };
List<Data> original = new List<Data> {d1, d2, d3};
List<Data> filterItems = new List<Data> {d4, d5, d6};
List<Data> result = original.FilterDataList(filterItems);
//How to call this method?
List<Data> genericCall = original.FilterList<Data>(filterItems, data => data.Id ?????????????)
}
}
public class Data
{
public long Id;
public string Name;
}
public static class Extensions
{
public static List<Data> FilterDataList(this List<Data> sourceList, List<Data> filterOutItems)
{
return sourceList.Where(p => filterOutItems.All(l => l.Id != p.Id)).ToList();
}
public static List<T> FilterList<T>(this List<T> sourceList, List<T> filterOutItems, Func<T, bool> filterExpression)
{
return sourceList.Where(p => filterOutItems.All(filterExpression)).ToList();
}
}
}
Thanks to everyone for pointing the LINQ Except extension out, here is my end solution
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
Data d1 = new Data {Id = 1, Name = "One"};
Data d2 = new Data { Id = 2, Name = "Two" };
Data d3 = new Data { Id = 3, Name = "Three" };
Data d4 = new Data { Id = 1, Name = "One" };
Data d5 = new Data { Id = 2, Name = "Two" };
List<Data> original = new List<Data> {d1, d2, d3};
List<Data> filterItems = new List<Data> {d4, d5, d6};
List<Data> datas = original.Except(filterItems, (x, y) => x.Id == y.Id).ToList();
}
}
public class Data
{
public long Id;
public string Name;
}
public static class EnumerableExtension
{
public static IEnumerable<T> Except<T>(this IEnumerable<T> listA, IEnumerable<T> listB,
Func<T, T, bool> lambda)
{
return listA.Except(listB, new Comparer<T>(lambda));
}
public static IEnumerable<T> Intersect<T>(this IEnumerable<T> listA, IEnumerable<T> listB,
Func<T, T, bool> lambda)
{
return listA.Intersect(listB, new Comparer<T>(lambda));
}
}
public class Comparer<T> : IEqualityComparer<T>
{
private readonly Func<T, T, bool> _expression;
public Comparer(Func<T, T, bool> lambda)
{
_expression = lambda;
}
public bool Equals(T x, T y)
{
return _expression(x, y);
}
public int GetHashCode(T obj)
{
/*
If you just return 0 for the hash the Equals comparer will kick in.
The underlying evaluation checks the hash and then short circuits the evaluation if it is false.
Otherwise, it checks the Equals. If you force the hash to be true (by assuming 0 for both objects),
you will always fall through to the Equals check which is what we are always going for.
*/
return 0;
}
}
}
If I understand your question correctly, FilterList is a generic version of FilterDataList where you are passing in the lambda as a parameter. In that case you would call the method as follows:
List<Data> genericCall = original.FilterList<Data>(filterItems, (x, y) => x.Id != y.Id);
If you want to use Except as #ivancho and #perelman have suggested you could use a method like this:
public static class EnumerableExtension
{
public static IEnumerable<T> Except<T>(this IEnumerable<T> listA, IEnumerable<T> listB,
Func<T, T, bool> lambda)
{
return listA.Except(listB, new Comparer<T>(lambda));
}
public static IEnumerable<T> Intersect<T>(this IEnumerable<T> listA, IEnumerable<T> listB,
Func<T, T, bool> lambda)
{
return listA.Intersect(listB, new Comparer<T>(lambda));
}
}
You would then call it as follows:
original.Except<Data>(filterItems, (x, y) => x.Id != y.Id);
What is your desired output? Did you try the first result in https://www.google.com/search?q=linq+intersect ? It seems like you should go through the Enumerable documentation - you are using .All where you most likely mean .Any, and just in general it would give you a better idea of what is possible with LINQ.
I am not clear what you are trying to do. Your FilterDataList appears to be the same as Except().ToList(). The .Where in your FilterList does not use p (the argument to the lambda), so I am unclear what you want to do with the filter expression. Maybe you are looking for using a different IEqualityComparer with Except() which you would have to define as a separate class.

How does Func<T,TResult> Work?

I am creating a Distinct extension method where I can pass in the criteria like the following.
persons.Distinct(p => p.Name);
I got the code from the web but I am having a hard time understanding the purpose of Func<T, TResult>. Also, when I say p => p.Name am I sending the String Name or am I sending the complete Person object? Here is the new Distinct method:
public static class ExtensionMethods
{
public static IEnumerable<T> Distinct<T>(
this IEnumerable<T> list, Func<T,object> checker)
{
return list.Distinct(new GenericComparer<T>(checker));
}
}
public class GenericComparer<T> : IEqualityComparer<T>
{
private Func<T, object> _checker;
public GenericComparer(Func<T,object> checker)
{
_checker = checker;
}
public bool Equals(T x, T y)
{
return _checker(x).Equals(_checker(y));
}
public int GetHashCode(T obj)
{
return _checker(obj).GetHashCode();
}
}
And here is the usage:
static void Main(string[] args)
{
var persons = new List<Person>()
{
new Person() { Id = 1, Name = "Mary"},
new Person() {Id = 2, Name="John"},
new Person() { Id = 3, Name = "Mary"}
};
var uniquePersons = persons.Distinct(p => p.Name);
foreach(var person in uniquePersons)
{
Console.WriteLine(person.Name);
}
}
When you do this:
persons.Distinct(p => p.Name);
You're basically creating a function on the fly (using lambda expressions), that looks like this:
string theFunction(Person p)
{
return p.Name;
}
This is a function that fits the signature of a Func<Person,String> delegate. The Distinct method can take a delegate (basically a function pointer) which it uses to determine whether or not an element is distinct - in your case, only unique strings (returned by the function above) will be considered "distinct" elements. This delegate is run on each element of your "persons" enumerable, and the results of those functions are used. It then creates a sequence (IEnumerable<Person>) from those elements.
Func<T, TResult>
defines a function that accepts one parameter (of type T) and returns an object (of type TResult).
In your case, if you want a function that takes a Person object and returns a string...you'd want
Func<Person, string>
which is the equivalent of:
string Function(Person p)
{
return p.Name;
}
You are getting back the distinct People, under the assumption that two People are the same if they have the same name
If you want a distinct set of names, you can use this:
IEnumerable<String> names = persons.Select(p => p.Name).Distinct();

Categories

Resources