Building a lambda WHERE expression to pass into a method - linq

I need to pass in a "where" lambda expression that'll be used in a LINQ query inside a method. The problem is, I don't know what the where value will be compared against until I get into the method.
Now to explain further and clarify some of what I said above I'll come up with a bit of a contrived example.
Imagine I have a List<Products> and I need to narrow that list down to a single record using a productId property of the Products object. Normally I would do this:
var product = productList.Where(p=>p.productId == 123).FirstOrDefault();
Now take it a step further - I need to put the above logic into a method that isn't limited to a List<Products> but is instead a List<T> so ideally, I'd be calling it like this (and I know the below won't work, it's simply here to show what I am trying to achieve):
myMethod(productList, p => p.productId == X)
With the caveat being that X isn't known until I'm inside the method.
Finally, for what it's worth, I need to point out that my collection of data is an OData DataServiceQuery.
So, to re-summarize my question: I need to know how to construct a lambda "where" expression that I can pass into a method and how to use it against a collection of objects in a LINQ query.

myMethod(productList, p => p.productId == X) - you can emulate with this trick
static void myMethod<T>(List<T> list, Func<T,bool> predicate, ref int x)
{
x = 5;
var v = list.Where(predicate);
foreach (var i in v)
Console.Write(i);
Console.ReadLine();
}
static void Main(string[] args)
{
List<int> x = new List<int> { 1, 2, 3, 4, 5 };
int z = 0;
myMethod(x, p => p == z, ref z);
}
but not sure if it solves your problem in whole

For one, if you are going to query an IEnumerable<T>, you will need to ensure that your comparison will work in the first place. In that case you can make your objects implement an interface that guarantees that they will support the comparison.
Once you do that, your method can have a generic constraint that limits the input to those interfaces. At that point, your method can take a Func, which can be passed to the LINQ Where clause:
public interface Identifier
{
int Id { get; set; }
}
public class Product : Identifier
{
public int Id { get; set; }
//Other stuff
}
public T GetMatch<T>(IEnumerable<T> collection, Func<T, int, bool> predicate) where T : Identifier
{
int comparison = 5;
return collection.Where(item => predicate(item, comparison)).FirstOrDefault();
}
Which can be invoked like:
var match = GetMatch<Identifier>(collection, (x, y) => x.Id == y);
UPDATE:
I modified the above code to take in a comparison parameter

You could try to use the PredicateBuilder class from the free LinqKit library(tutorial).
You can then construct a predicate using
PredicateBuilder predicate = PredicateBuilder.True<T>();
predicate = PredicateBuilder.And(predicate, p=> p.product_id == X);
where X is of type T.
You can use this predicate in a where clause such as .Where(predicate) and return an IQueryable or return the predicate itself which would be of type Expression<Func<T, bool>>

Related

Comparable class with a List<String> field

I have a simple class which stores an integer and a list of Strings.
As I want to use this class in a TreeSet<>, the one must be Comparable.
But when trying to use the Java 8 Comparator class, I cannot compare my inner list.
I have the following error:
Bad return type in method reference: cannot convert java.util.List to U
I think there is a very simple way to do that but I could not find it out.
How to do that?
public class MyClass implements Comparable<MyClass> {
private final int someInt;
private final List<String> someStrings;
public MyClass (List<String> someStrings, int someInt) {
this.someInt = someInt;
this.someStrings = new ArrayList<>(someStrings);
}
#Override
public int compareTo(MyClass other) {
return
Comparator.comparing(MyClass::getSomeInt)
.thenComparing(MyClass::getSomeStrings) // Error here
.compare(this, other);
}
public int getSomeInt() {
return someInt;
}
public List<String> getSomeStrings() {
return someStrings;
}
}
Edit 1
I just want the String list to be compared in the simplest way (using implicitly String.compareTo()).
Note that I do now want to sort my List<String> but I want it to be Comparable so that MyClass is also comparable and finally, I can insert MyClass instances into a TreeSet<MyClass>.
A also saw in the JavaDoc the following:
java.util.Comparator<T> public Comparator<T>
thenComparing(#NotNull Comparator<? super T> other)
For example, to sort a collection of String based on the length and then case-insensitive natural ordering, the comparator can be composed using following code,
Comparator<String> cmp = Comparator.comparingInt(String::length)
.thenComparing(String.CASE_INSENSITIVE_ORDER);
It seems to be an clue but I don't know how to apply it to this simple example.
Edit 2
Let's say I want my List<String> to be sorted the following way:
First check: List.size() (the shorter is less than the larger one);
Second check if sizes match: comparing one by one each element of both Lists until finding one where the String.compareTo method returns 1 or -1.
How to do that with lambdas in a my compareTo method?
Edit 3
This does not duplicates this question because I want to know how to build a comparator of a class which contains a List<String> with Java 8 chaining Comparable calls.
So to compare the list, first you check the length, then you compare each item with same indexes in both list one by one right?
(That is [a, b, c] < [b, a, c])
Make a custom comparator for list return join of your list string:
Comparator<List<String>> listComparator = (l1, l2) -> {
if (l1.size() != l2.size()) {
return l1.size() - l2.size();
}
for (int i = 0; i < l1.size(); i++) {
int strCmp = l1.get(i).compareTo(l2.get(i));
if (strCmp != 0) {
return strCmp;
}
}
return 0; // Two list equals
};
Then you can compare using that custom comparator:
#Override
public int compareTo(MyClass other) {
return Comparator.comparing(MyClass::getSomeInt)
.thenComparing(Comparator.comparing(MyClass:: getSomeStrings , listComparator))
.compare(this, other);
}
If you want [a, b, c] = [b, a, c], then you have to sort those list first before comparing:
public String getSomeStringsJoined() {
return getSomeStrings().stream().sort(Comparator.naturalOrder()).collect(Collectors.joining());
}

Can Linq project an List of int to another list of class T

I have a list of int and I wonder if I can create another list of object T based on the previous list using Linq.
To simplify the issue:
I have a list of int like that: 1,2,3,4
and I expect to have (1,2), (2,4), (3,6), (4,8)
Normally, we can do that easily without Linq
public class T
{
int first;
int Second;
public T(int x, int y)
{
first = x;
Second = y;
}
}
class Program
{
static void Main(string[] args)
{
List<int> series = new List<int>() { 1,2,3,4 };
List<T> obj = new List<T>();
foreach (int item in series)
{
obj.Add(new T(item,item*2));
}
}
}
That worked perfectly.
But when I tried to use Linq
List<T> obj = series.Select(x=> {new T(x,x*2)}).ToList<T>();
I thought it would work but I got an error saying
Error 2 The type arguments for method 'System.Linq.Enumerable.Select<TSource,TResult>(System.Collections.Generic.IEnumerable<TSource>, System.Func<TSource,int,TResult>)' cannot be inferred from the usage. Try specifying the type arguments explicitly.
What have I done incorrectly? I am still a newbie (of probably a few month old) learning Linq :)
Get rid of the curly braces...
List<T> obj = series.Select(x=> new T(x,x*2)).ToList<T>();
When you write a lambda like:
x => x * 2
It's assumed that the right side is the return value. When you use curly braces, it's expecting you to actually use the return keyword, like this:
x => { return x * 2; }
When you don't, I bet it's assuming the lambda returns void.

Can I get a Func object for an Extension method

I have a small utility extension method that performs some null checks on some LINQ extension methods in IEnumerable<T>. The code looks like this
public static class MyIEnumerableExtensions
{
// Generic wrapper to allow graceful handling of null values
public static IEnumerable<T> NullableExtension<T>(this IEnumerable<T> first, IEnumerable<T> second, Func<IEnumerable<T>, IEnumerable<T>, IEnumerable<T>> f)
{
if (first == null && second == null) return Enumerable.Empty<T>();
if (first == null) return second;
if (second == null) return first;
return f(first, second);
}
// Wrap the Intersect extension method in our Nullable wrapper
public static IEnumerable<T> NullableIntersect<T>(this IEnumerable<T> first, IEnumerable<T> second)
{
// It'd be nice to write this as
//
// return first.NullableExtension<T>(second, IEnumerable<T>.Intersect );
//
return first.NullableExtension<T>(second, (a,b) => a.Intersect(b));
}
}
So, is there a way to pass in the IEnumerable<T>.Intersect extension method to NullableExtension directly rather than wrapping it in a lambda?
Edit
Because it is actually concise to pass in the Enumerable extension method, I removed the NullableIntersect (and other) methods and just call the nullable wrapper directly.
Also, as Anthony points out, the semantics of what an Empty enumerable should do is different depending on the extension method, i.e. Union versus Intersect. As such, I rename the NullableExtension method to IgnoreIfNull which better reflects the generic behavior.
public static class MyIEnumerableExtensions
{
// Generic wrappers to allow graceful handling of null values
public static IEnumerable<T> IgnoreIfNull<T>(this IEnumerable<T> first, IEnumerable<T> second, Func<IEnumerable<T>, IEnumerable<T>, IEnumerable<T>> f)
{
if (first == null && second == null) return Enumerable.Empty<T>();
if (first == null) return second;
if (second == null) return first;
return f(first, second);
}
public static IEnumerable<T> EmptyIfNull<T>(this IEnumerable<T> first, IEnumerable<T> second, Func<IEnumerable<T>, IEnumerable<T>, IEnumerable<T>> f)
{
return f(first ?? Enumerable.Empty<T>(), second ?? Enumerable.Empty<T>());
}
}
// Usage example. Returns { 1, 4 } because arguments to Union and Intersect are ignored
var items = new List<int> { 1, 4 };
var output1 = items.IgnoreIfNull(null, Enumerable.Union).IgnoreIfNull(null, Enumerable.Intersect);
// Usage example. Returns { } because arguments to Union and Intersect are set to empty
var output2 = items.EmptyIfNull(null, Enumerable.Union).EmptyIfNull(null, Enumerable.Intersect);
Intersect is defined within static class Enumerable. You can pass it into your method like below
return first.NullableExtension<T>(second, Enumerable.Intersect);
Note: You might be concerned about the behavior of your logic in the case of a null sequence. For example, in the case of
List<int> first = null;
var second = new List<int> { 1, 4 };
var output = first.NullableIntersect(second).ToList();
You have defined it such that output contains {1, 4} (the elements of second). I might expect first to instead be treated as an empty sequence, and an intersection with second would result in an empty sequence. Ultimately, that's for you to decide the behavior you desire.

Linq Union - IEqualityComparer and # of executions

Out of interest how does the GetHashCode of a concrete implementation of IEqualityComparer work?
The reason that I ask is that I'm using linq to union two collections, and when only the left collection has an item GetHashCode is called twice. Further to that, it's called four times if both collections have one row.
This is rough typing but you'll get the point. GetHashCode is called twice, which I'm guessing is twice for the one item in listOne?
e.g.
var listOne = new List<SearchResult>{new SearchResult{Name="Blah"}};
var listTwo = new List<SearchResult>();
listOne.Union(listTwo, SearchResultComparer);
public class SearchResultComparer : IEqualityComparer<SearchResult>
{
public bool Equals(SearchResult x, SearchResult y){....}
public int GetHashCode(SearchResult obj)
{
unchecked
{
int result = 0;
result = (result * 397) ^ (obj.Name != null ?
return result;
}
}
}
Thanks
I'm curious about your observation, I can only observe a single check of GetHashCode for each of the items in each list. But as far as an implementation of Union using your comparer, think of it like this
static IEnumerable<T> Union<T>(this IEnumerable<T> first, IEnumerable<T> second, IEqualityComparer<T> comparer)
{
// there's undoubtedly validation against null sequences
var unionSet = new HashSet<T>(comparer);
foreach (T item in first)
{
if (unionSet.Add(item))
yield return item;
}
foreach (T item in second)
{
if (unionSet.Add(item))
yield return item;
}
}
The Add method of the HashSet will return true or false if the item can be added. In the inner implementation, it will make a call to the item's GetHashCode and get the value, and then see if this value already exists inside the collection. If it does, it compares each with the matching hash code for equality. If there is no equality match (or if the hash code did not already exist), the item is successfully added and the method returns true. Otherwise, the item is not added and the method returns false.

Using Distinct with LINQ and Objects [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 9 months ago.
The community reviewed whether to reopen this question 9 months ago and left it closed:
Original close reason(s) were not resolved
Improve this question
Until recently, I was using a Distinct in LINQ to select a distinct category (an enum) from a table. This was working fine.
I now need to have it distinct on a class containing a category and country (both enums). The Distinct isn't working now.
What am I doing wrong?
I believe this post explains your problem:
http://blog.jordanterrell.com/post/LINQ-Distinct()-does-not-work-as-expected.aspx
The content of the above link can be summed up by saying that the Distinct() method can be replaced by doing the following.
var distinctItems = items
.GroupBy(x => x.PropertyToCompare)
.Select(x => x.First());
try an IQualityComparer
public class MyObjEqualityComparer : IEqualityComparer<MyObj>
{
public bool Equals(MyObj x, MyObj y)
{
return x.Category.Equals(y.Category) &&
x.Country.Equals(y.Country);
}
public int GetHashCode(MyObj obj)
{
return obj.GetHashCode();
}
}
then use here
var comparer = new MyObjEqualityComparer();
myObjs.Where(m => m.SomeProperty == "whatever").Distinct(comparer);
You're not doing it wrong, it is just the bad implementation of .Distinct() in the .NET Framework.
One way to fix it is already shown in the other answers, but there is also a shorter solution available, which has the advantage that you can use it as an extension method easily everywhere without having to tweak the object's hash values.
Take a look at this:
**Usage:**
var myQuery=(from x in Customers select x).MyDistinct(d => d.CustomerID);
Note: This example uses a database query, but it does also work with an enumerable object list.
Declaration of MyDistinct:
public static class Extensions
{
public static IEnumerable<T> MyDistinct<T, V>(this IEnumerable<T> query,
Func<T, V> f)
{
return query.GroupBy(f).Select(x=>x.First());
}
}
Or if you want it shorter, this is the same as above, but as "one-liner":
public static IEnumerable<T> MyDistinct<T, V>(this IEnumerable<T> query, Func<T, V> f)
=> query.GroupBy(f).Select(x => x.First());
And it works for everything, objects as well as entities. If required, you can create a second overloaded extension method for IQueryable<T> by just replacing the return type and first parameter type in the example I've given above.
Test data:
You can try it out with this test data:
List<A> GetData()
=> new List<A>()
{
new A() { X="1", Y="2" }, new A() { X="1", Y="2" },
new A() { X="2", Y="3" }, new A() { X="2", Y="3" },
new A() { X="1", Y="3" }, new A() { X="1", Y="3" },
};
class A
{
public string X;
public string Y;
}
Example:
void Main()
{
// returns duplicate rows:
GetData().Distinct().Dump();
// Gets distinct rows by i.X
GetData().MyDistinct(i => i.X).Dump();
}
For explanation, take a look at other answers. I'm just providing one way to handle this issue.
You might like this:
public class LambdaComparer<T>:IEqualityComparer<T>{
private readonly Func<T,T,bool> _comparer;
private readonly Func<T,int> _hash;
public LambdaComparer(Func<T,T,bool> comparer):
this(comparer,o=>0) {}
public LambdaComparer(Func<T,T,bool> comparer,Func<T,int> hash){
if(comparer==null) throw new ArgumentNullException("comparer");
if(hash==null) throw new ArgumentNullException("hash");
_comparer=comparer;
_hash=hash;
}
public bool Equals(T x,T y){
return _comparer(x,y);
}
public int GetHashCode(T obj){
return _hash(obj);
}
}
Usage:
public void Foo{
public string Fizz{get;set;}
public BarEnum Bar{get;set;}
}
public enum BarEnum {One,Two,Three}
var lst=new List<Foo>();
lst.Distinct(new LambdaComparer<Foo>(
(x1,x2)=>x1.Fizz==x2.Fizz&&
x1.Bar==x2.Bar));
You can even wrap it around to avoid writing noisy new LambdaComparer<T>(...) thing:
public static class EnumerableExtensions{
public static IEnumerable<T> SmartDistinct<T>
(this IEnumerable<T> lst, Func<T, T, bool> pred){
return lst.Distinct(new LambdaComparer<T>(pred));
}
}
Usage:
lst.SmartDistinct((x1,x2)=>x1.Fizz==x2.Fizz&&x1.Bar==x2.Bar);
NB: works reliably only for Linq2Objects
I know this is an old question, but I am not satisfied with any of the answers. I took time to figure this out for myself and I wanted to share my findings.
First it is important to read and understand these two things:
IEqualityComparer
EqualityComparer
Long story short in order to make the .Distinct() extension understand how to determine equality of your object - you must define a "EqualityComparer" for your object T. When you read the Microsoft docs it literally states:
We recommend that you derive from the EqualityComparer class
instead of implementing the IEqualityComparer interface...
That is how you determine what to use, because it had been decided for you already.
For the .Distinct() extension to work successfully you must ensure that your objects can be compared accurately. In the case of .Distinct() the GetHashCode() method is what really matters.
You can test this out for yourself by writing a GetHashCode() implementation that just returns the current Hash Code of the object being passed in and you will see the results are bad because this value changes on each run. That makes your objects too unique which is why it is important to actually write a proper implementation of this method.
Below is an exact copy of the code sample from IEqualityComparer<T>'s page with test data, small modification to the GetHashCode() method and comments to demonstrate the point.
//Did this in LinqPad
void Main()
{
var lst = new List<Box>
{
new Box(1, 1, 1),
new Box(1, 1, 1),
new Box(1, 1, 1),
new Box(1, 1, 1),
new Box(1, 1, 1)
};
//Demonstration that the hash code for each object is fairly
//random and won't help you for getting a distinct list
lst.ForEach(x => Console.WriteLine(x.GetHashCode()));
//Demonstration that if your EqualityComparer is setup correctly
//then you will get a distinct list
lst = lst
.Distinct(new BoxEqualityComparer())
.ToList();
lst.Dump();
}
public class Box
{
public Box(int h, int l, int w)
{
this.Height = h;
this.Length = l;
this.Width = w;
}
public int Height { get; set; }
public int Length { get; set; }
public int Width { get; set; }
public override String ToString()
{
return String.Format("({0}, {1}, {2})", Height, Length, Width);
}
}
public class BoxEqualityComparer
: EqualityComparer<Box>
{
public override bool Equals(Box b1, Box b2)
{
if (b2 == null && b1 == null)
return true;
else if (b1 == null || b2 == null)
return false;
else if (b1.Height == b2.Height && b1.Length == b2.Length
&& b1.Width == b2.Width)
return true;
else
return false;
}
public override int GetHashCode(Box bx)
{
#region This works
//In this example each component of the box object are being XOR'd together
int hCode = bx.Height ^ bx.Length ^ bx.Width;
//The hashcode of an integer, is that same integer
return hCode.GetHashCode();
#endregion
#region This won't work
//Comment the above lines and uncomment this line below if you want to see Distinct() not work
//return bx.GetHashCode();
#endregion
}
}

Resources