How to write IEqualityComparer for anonymous variables in lambda expression? - c#

I want to know there is a way to implement IEqualityComparer for anonymous variables in a lambda expression or, in any case, I need to write class to transform anonymous variables to the sprecific class and create a class where I need to implement IEqualtyComparer ?
I write code which create Cartesian(Decart's) production:
I defined class Decart.
public class Decart
{
public int X;
public int Y;
}
I defined IEqualtityComparer for Decart class
public class Ext : IEqualityComparer<Decart>
{
public bool Equals(Decart x, Decart y)
{
if ((x.X == y.X && x.Y == y.Y) ||
x.X == y.Y && x.Y == y.X)
return true;
return false;
}
public int GetHashCode(Decart obj)
{
return obj.X + obj.Y;
}
}
I run this code:
static void Main(string[] args)
{
Ext ext = new Ext();
IEnumerable<int> input = Enumerable.Range(1, 3);
var secondResult = input
.SelectMany(x => input.Select(y => new Decart{ X = x, Y = y }))
.Distinct(new Ext());
Console.WriteLine(new string('-', 50));
foreach (var x in secondResult)
{
Console.WriteLine(string.Format("{0} {1}", x.X, x.Y));
}
//output:
//1 1
//1 2
//1 3
//2 2
//2 3
//3 3
}
I want to run next code without defining a class for anonymous variables, a class for implementing IEqualityComparer.
var thirdResult = input
.SelectMany(x => input
.SelectMany(y => input
.Select(z => new { x, y, z })))
.Distinct( ???? );
//in this case output need to be like this:
//1 1 1
//1 2 1
//1 3 1
//2 1 2
//2 2 2
//2 3 2
//3 1 3
//3 2 3
//3 3 3
How to do it ?

You can declare IEqualityComparer<T> implementation which would take delegates as implementation for GetHashCode and Equals methods of interface. Then you can pass-in anonymous methods as implementation.
public static IEqualityComparer<T> CreateEqualityComparer<T>(T ignore, Func<T, int> getHashCode, Func<T, T, bool> equals) => new DelegatedEqualityComparer<T>(getHashCode, equals);
public class DelegatedEqualityComparer<T> : EqualityComparer<T> {
private Func<T, int> getHashCode;
private Func<T, T, bool> equals;
public DelegatedEqualityComparer(Func<T, int> getHashCode, Func<T, T, bool> equals) {
if(getHashCode==null) throw new ArgumentNullException(nameof(getHashCode));
if(equals==null) throw new ArgumentNullException(nameof(equals));
this.getHashCode=getHashCode;
this.equals=equals;
}
public override int GetHashCode(T x) => getHashCode(x);
public override bool Equals(T x, T y) => equals(x, y);
}
And you use it like this:
var equalityComparer = CreateEqualityComparer(true ? null : new { x = 0, y = 0 }, a => a.x+a.y, (a, b) => (a.x==b.x&&a.y==b.y)||(a.x==b.y&&a.y==b.x));
var result = input
.SelectMany(x => input
.Select(y => new { x, y }))
.Distinct(equalityComparer);
Meaning of true ? null : new { x = 0, y = 0 }:
First argument to CreateEqualityComparer (T ignore) is needed to allow compiler to infer type T, as you can not spell name of anonymous type. true condition of ternary operator make compiler to always select left branch null, but as both branches of ternary operator must return the same type, then new { x = 0, y = 0 } make compiler to implicitly cast null to given anonymous type.
Also, relevant note from specification:
7.6.10.6 Anonymous object creation expressions
Within the same program, two anonymous object initializers that specify a sequence of properties of the same names and compile-time types in the same order will produce instances of the same anonymous type.

It's unclear what you're asking.
I assume you want to generilize the dimensions of this class like
public class Decart
{
public int[] dim;
}
then you can extend the comparer
public class Ext : IEqualityComparer<Decart>
{
public bool Equals(Decart x, Decart y)
{
for(int i=0; i< x.dim.Length;i++)
if (x.dim[i] != y.dim[i] )
return false;
return true;
}
public int GetHashCode(Decart obj)
{
return obj.dim.Sum();
}
}

Related

How do I create one generic dot product method for various number types

I have the following function:
public static Func<int[], int[], int> Foo()
{
Func<int[], int[], int> result = (first, second) => first.Zip(second, (x, y) => x * y).Sum();
return result;
}
I would like to create same Func but for various number types (long, short, etc. and not only int).
The code below does not work. I receive the following error
(CS0019: Operator '*' cannot be applied to operands of type 'T' and 'T'):
public static Func<T[], T[], T> Foo<T>() where T : struct
{
Func<T[], T[], T> result = (first, second) => first.Zip(second, (x, y) => x * y).Sum();
return result;
}
After some investigation I concluded that I need to generate code dynamically with expression trees, however, I could not find any useful resource on web. The ones I found only deal with very simple lambda expressions. I also tried to use reflection<> and ILSpy to peek into C#1 code automatically with the idea to manually change ints to Ts. However, it did not work - I think due to (RuntimeMethodHandle)/OpCode not supported: LdMemberToken/. Any Help would be appreciated. I am really interested in to solve this.
public static Expression<Func<int[], int[], int>> Foo()
{
ParameterExpression parameterExpression = Expression.Parameter(typeof(int[]), "first");
ParameterExpression parameterExpression2 = Expression.Parameter(typeof(int[]), "second");
MethodInfo method = (MethodInfo)MethodBase.GetMethodFromHandle((RuntimeMethodHandle)/*OpCode not supported: LdMemberToken*/);
Expression[] array = new Expression[1];
MethodInfo method2 = (MethodInfo)MethodBase.GetMethodFromHandle((RuntimeMethodHandle)/*OpCode not supported: LdMemberToken*/);
Expression[] obj = new Expression[3] { parameterExpression, parameterExpression2, null };
ParameterExpression parameterExpression3 = Expression.Parameter(typeof(int), "x");
ParameterExpression parameterExpression4 = Expression.Parameter(typeof(int), "y");
obj[2] = Expression.Lambda<Func<int, int, int>>(Expression.Multiply(parameterExpression3, parameterExpression4), new ParameterExpression[2] { parameterExpression3, parameterExpression4 });
array[0] = Expression.Call(null, method2, obj);
return Expression.Lambda<Func<int[], int[], int>>(Expression.Call(null, method, array), new ParameterExpression[2] { parameterExpression, parameterExpression2 });
}
Generic math is an upcoming feature that is in preview right now. So in the future, "static abstract interface members" are the way to handle this. If you opt in for preview features, you can write valid C# code like this:
public static Func<T[], T[], T> Foo<T>()
where T :
unmanaged,
IMultiplyOperators<T, T, T>,
IAdditiveIdentity<T, T>,
IAdditionOperators<T, T, T>
{
Func<T[], T[], T> result =
static (first, second) => first.Zip(second, (x, y) => x * y).Sum();
return result;
}
// generic sum doesn't exist yet in linq
public static T Sum<T>(this IEnumerable<T> source)
where T :
unmanaged,
IAdditionOperators<T, T, T>,
IAdditiveIdentity<T, T>
{
T sum = T.AdditiveIdentity;
foreach (var item in source)
{
sum += item;
}
return sum;
}
It is still going to be some time before generic math releases and there are some unresolved problems with it (such as not being able to do "checked" math), so to actually answer your question, why not just use dynamic?
public static Func<T[], T[], T> Foo<T>() where T : struct
{
Func<T[], T[], T> result = (first, second) => DynamicDotProduct(first.Zip(second));
return result;
}
private static T DynamicDotProduct<T>(IEnumerable<(T first, T second)> zipped) where T : struct
{
// here I am assuming default(T) is zero of that type
dynamic sum = default(T);
foreach((dynamic x, T y) in zipped)
{
sum += x * y;
}
return sum;
}
If you are old school you can use Expressions to build up generic math
using System.Numerics;
internal class Program
{
static void Main(string[] args)
{
int[] i_a = { 1, 2, 3, 4 };
int[] i_b = { 7, 6, 5, 4 };
int i_dot = DotProduct(i_a, i_b);
// 50
float[] f_a = { 1f, 2f, 3f, 4f };
float[] f_b = { 7f, 6f, 5f, 4f };
float f_dot = DotProduct(f_a, f_b);
// 50f
Vector2[] v_a = { new Vector2(1, 2), new Vector2(3, 4) };
Vector2[] v_b = { new Vector2(7, 6), new Vector2(5, 4) };
Vector2 v_dot = DotProduct(v_a, v_b);
// [22f, 28f]
}
public static T DotProduct<T>(T[] left, T[] right)
{
if (left.Length==right.Length && left.Length>0)
{
// Use generic math defined in Operation<T>
T sum = Operation<T>.Mul(left[0], right[0]);
for (int i = 1; i < left.Length; i++)
{
sum = Operation<T>.Add(sum, Operation<T>.Mul(left[i], right[i]));
}
return sum;
}
return default(T);
}
}
public static class Operation<T>
{
static Operation()
{
var arg1 = Expression.Parameter(typeof(T));
var arg2 = Expression.Parameter(typeof(T));
Add = Expression.Lambda<Func<T, T, T>>(Expression.Add(arg1, arg2), arg1, arg2).Compile();
Mul = Expression.Lambda<Func<T, T, T>>(Expression.Multiply(arg1, arg2), arg1, arg2).Compile();
}
///<summary>Generic Addition</summary>
public static Func<T, T, T> Add { get; }
///<summary>Generic Multiplication</summary>
public static Func<T, T, T> Mul { get; }
}
So any class that defines op_Addition and op_Multiplication, or the equivalent operators can be used with Operation<T>.Add and Operation<T>.Mul
Here System.Numerics.Vector2 defines the following operators, so you don't have to.
public static Vector2 operator +(Vector2 left, Vector2 right)
{
return new Vector2(left.X + right.X, left.Y + right.Y);
}
public static Vector2 operator *(Vector2 left, Vector2 right)
{
return new Vector2(left.X * right.X, left.Y * right.Y);
}

.NET 6 IntersectBy and ExceptBy examples

Could someone provide me a small example on how to Use the .NET 6 LINQ IntersectBy and ExceptBy methods? MSDN hasn't got any examples and the one I tried doesn't compile due to CS0411 error. The example I tried:
namespace Test
{
internal struct Example
{
public int X { get; set; }
public int Y { get; set; }
public override string ToString()
{
return $"{X}, {Y}";
}
}
public class Program
{
public static void Main()
{
var elements = new List<Example>
{
new Example { X = 10, Y = 20 },
new Example { X = 11, Y = 23 },
};
var elements2 = new List<Example>
{
new Example { X = 10, Y = 12 },
new Example { X = 44, Y = 20 },
};
//ok
var union = elements.UnionBy(elements2, x => x.X);
//CS0411 - Why ?
var intersect = elements.IntersectBy(elements2, x => x.X);
//CS0411 - Why ?
var except = elements.ExceptBy(elements2, x => x.X);
Console.ReadKey();
}
}
}
Granted the documentation doesn't have any examples, it states that the selector function should select TKey i.e. the type of the second collection. The following should work:
var intersect = elements.IntersectBy(elements2, x => x);
var except = elements.ExceptBy(elements2, x => x);
Although I think this may be closer to what you want:
var intersect = elements.IntersectBy(elements2.Select(e => e.X), x => x.X);
For more complex types, you may want to consider implementing an IEqualityComparer and using the overloads that take one as an argument.
I made my own ExceptByProperty method like this
Usage:
var new = items.ExceptByProperty(duplicateItems, x => x.Id).ToList();
Code:
public static class EnumerableExtensions
{
public static IEnumerable<TSource> ExceptByProperty<TSource, TProperty>(this IEnumerable<TSource> first, IEnumerable<TSource> second, Func<TSource, TProperty> keySelector)
{
return first.ExceptBy(second, x => x, GenericComparer<TSource, TProperty>.Comparer(keySelector));
}
}
public sealed class GenericComparer<T, TProperty> : IEqualityComparer<T>
{
public static IEqualityComparer<T> Comparer(Func<T, TProperty> selector)
{
return new GenericComparer<T, TProperty>(selector);
}
private readonly Func<T, TProperty> selector;
public GenericComparer(Func<T, TProperty> selector)
{
this.selector = selector;
}
public bool Equals(T? x, T? y)
{
if (x == null || y == null) return false;
return Equals(selector(x), selector(y));
}
public int GetHashCode([DisallowNull] T obj)
{
object? value = selector(obj);
if (value == null) return obj.GetHashCode();
return value.GetHashCode();
}
}

Sort objects by string propery, empty string last

I have an array of objects which all contain string property. I want to sort objects by string property alphabetically in a way that objects with empty string property come at the end of the list. Currently I have this:
switches = switches.OrderBy(n => n.GetCurrentUser()).ToArray();
The problem is that it puts empty strings at the top of the list. How do I put objects with strings with value (sorted alphabetically) at the top and objects with empty strings at the bottom?
You can use:
switches = switches
.Select(n => new { TheObject = n, User = n.GetCurrentUser() })
.OrderBy(x => String.IsNullOrEmpty(x.User) ? 1 : 0)
.ThenBy(x => x.User)
.Select(x => x.TheObject)
.ToArray();
This will first build two groups, the one with empty user and others. OrderBy will move them to the end because 1 is more than 0. If you want them at the top use OrderByDescending.
Then i use ThenBy to sort alphabetically which will only matter for the non-empty users.
You can also use inline Comparer creation:
switches.OrderBy(n => n.GetCurrentUser(),
Comparer<string>.Create((a, b) =>
string.IsNullOrEmpty(a) && !string.IsNullOrEmpty(b)? 1
: !string.IsNullOrEmpty(a) && string.IsNullOrEmpty(b) ? -1
: string.Compare(a, b)));
OrderBy has an overload that accepts an IComparer<>T. This allows you to define your own sorting rules. You can start with the generic Comparer class and override the Compare method, eg :
public class EmptyLastComparer: Comparer<string>
{
public override int Compare(string x, string y)
{
if (String.IsNullOrWhiteSpace(x) && !String.IsNullOrWhiteSpace(y))
{
return 1;
}
else if (String.IsNullOrWhiteSpace(x) && String.IsNullOrWhiteSpace(y))
{
return 0;
}
else if (!String.IsNullOrWhiteSpace(x) && String.IsNullOrWhiteSpace(y))
{
return -1;
}
else
{
return x.CompareTo(y);
}
}
}
To use it, creatre a new EmptyLastComparer() instance and pass it to OrderBy :
var myStrings = new[] { "c", "A","a", "A","b", " "," ",null };
var ordered=myStrings.OrderBy(x => x, new EmptyLastComparer());
String comparison is more complex than just comparing two strings. String.Compare has overloads that allow case-insensitive comparisons, using specific cultures etc. The custom comparer could accepts a StringComparison parameter in its constructor to allow something similar, eg :
public class EmptyLastComparer : Comparer<string>
{
private readonly StringComparison _comparison;
public EmptyLastComparer(StringComparison comparison=StringComparison.CurrentCulture)
{
_comparison = comparison;
}
public override int Compare(string x, string y)
{
if (String.IsNullOrWhiteSpace(x) && !String.IsNullOrWhiteSpace(y))
{
return 1;
}
else if (String.IsNullOrWhiteSpace(x) && String.IsNullOrWhiteSpace(y))
{
return 0;
}
else if (!String.IsNullOrWhiteSpace(x) && String.IsNullOrWhiteSpace(y))
{
return -1;
}
else
{
return String.Compare(x,y, _comparison);
}
}
}
Perhaps even add some predefined comparers, just like StringComparer does :
public static EmptyLastComparer CurrentCulture =>
new EmptyLastComparer();
public static EmptyLastComparer CurrentCultureIgnoreCase =>
new EmptyLastComparer(StringComparison.CurrentCultureIgnoreCase);
public static EmptyLastComparer InvariantCulture =>
new EmptyLastComparer(StringComparison.InvariantCulture);
public static EmptyLastComparer InvariantCultureIgnoreCase =>
new EmptyLastComparer(StringComparison.InvariantCultureIgnoreCase);
public static EmptyLastComparer Ordinal =>
new EmptyLastComparer(StringComparison.Ordinal);
public static EmptyLastComparer OrdinalIgnoreCase =>
new EmptyLastComparer(StringComparison.OrdinalIgnoreCase);
And use them the same way, without allocating a new comparer each time :
var ordered=myStrings.OrderBy(x => x, EmptyLastComparer.InvariantCultureIgnoreCase);

Generic method to compare 2 strongly typed list

I have the following method that compares 2 list (of the same type) and returns the differences. How do I make this method accept lists of any type?
var differences = list1.Where(x => list2.All(x1 => x1.Name != x.Name))
.Union(list2.Where(x => list1.All(x1 => x1.Name != x.Name)));
To get the difference between two sets (with order independency and multiplicity independency), you can use: HashSet<T>.SymmetricExceptWith(IEnumerable<T>).
public static IEnumerable<T> GetSymmetricDifference<T>(IEnumerable<T> list1, IEnumerable<T> list2, IEqualityComparer<T> comparer = null)
{
HashSet<T> result = new HashSet<T>(list1, comparer);
result.SymmetricExceptWith(list2);
return result;
}
In your case, to use it:
var difference = GetSymmetricDifference(list1, list2, new MyComparer());
With a custom comparer:
public class MyComparer : IEqualityComparer<MyType>
{
public bool Equals(MyType x, MyType y)
{
return x.Name.Equals(y.Name);
}
public int GetHashCode(MyType obj)
{
return obj.Name == null ? 0 : obj.Name.GetHashCode();
}
}
What about this:
var differences = list1.Except(list2).Union(list2.Except(list1));

What is the cleanest way to do an outer join without equals?

I have two lists, I need to find the items in the first list that are missing from the second, but I can only compare them with a Boolean function.
class A
{
internal bool Matching(A a)
{
return true;
}
}
class OuterMatch
{
List<A> List1 = new List<A>();
List<A> List2 = new List<A>();
void BasicOuterJoin()
{
// textbook example of an outer join, but it does not use my Matching function
var missingFrom2 = from one in List1
join two in List2
on one equals two into matching
from match in matching.DefaultIfEmpty()
where match == null
select one;
}
void Matching()
{
// simple use of the matching function, but this is an inner join.
var matching = from one in List1
from two in List2
where one.Matching(two)
select one;
}
void MissingBasedOnMatching()
{
// a reasonable substitute for what I'm after
var missingFrom2 = from one in List1
where (from two in List2
where two.Matching(one)
select two)
.Count() == 0
select one;
}
MissingBasedOnMatching gives me the right results, but it's not visually obviously an outer join like BasicOuterJoin is. Is there a clearer way to do this?
There's a form of GroupJoin that takes a comparison operator, but I'm not clear if there is a way to use it to make an outer join.
I've been using some useful (and short!) code from a blog by Ed Khoze.
He's posted a handy class which provides an adapter so that you can use Enumerable.Except() with a lambda.
Once you have that code, you can use Except() to solve your problem like so:
var missing = list1.Except(list2, (a, b) => a.Matching(b));
Here's a complete compilable sample. Credit to Ed Khoze for the LINQHelper class:
using System;
using System.Collections.Generic;
using System.Linq;
namespace Demo
{
class A
{
public int Value;
public bool Matching(A a)
{
return a.Value == Value;
}
public override string ToString()
{
return Value.ToString();
}
}
class Program
{
void test()
{
var list1 = new List<A>();
var list2 = new List<A>();
for (int i = 0; i < 20; ++i) list1.Add(new A {Value = i});
for (int i = 4; i < 16; ++i) list2.Add(new A {Value = i});
var missing = list1.Except(list2, (a, b) => a.Matching(b));
missing.Print(); // Prints 0 1 2 3 16 17 18 19
}
static void Main()
{
new Program().test();
}
}
static class MyEnumerableExt
{
public static void Print<T>(this IEnumerable<T> sequence)
{
foreach (var item in sequence)
Console.WriteLine(item);
}
}
public static class LINQHelper
{
private class LambdaComparer<T>: IEqualityComparer<T>
{
private readonly Func<T, T, bool> _lambdaComparer;
private readonly Func<T, int> _lambdaHash;
public LambdaComparer(Func<T, T, bool> lambdaComparer) :
this(lambdaComparer, o => 0)
{
}
private LambdaComparer(Func<T, T, bool> lambdaComparer, Func<T, int> lambdaHash)
{
if (lambdaComparer == null)
throw new ArgumentNullException("lambdaComparer");
if (lambdaHash == null)
throw new ArgumentNullException("lambdaHash");
_lambdaComparer = lambdaComparer;
_lambdaHash = lambdaHash;
}
public bool Equals(T x, T y)
{
return _lambdaComparer(x, y);
}
public int GetHashCode(T obj)
{
return _lambdaHash(obj);
}
}
public static IEnumerable<TSource> Except<TSource>
(
this IEnumerable<TSource> enumerable,
IEnumerable<TSource> second,
Func<TSource, TSource, bool> comparer
)
{
return enumerable.Except(second, new LambdaComparer<TSource>(comparer));
}
}
}
If your problem statement is actually
Find all members of X that do not exist in Y
And given a class Foo that implements IEquatable<Foo> (pretty much what your Matching method does):
class Foo : IEquatable<Foo>
{
public bool Equals( Foo other )
{
throw new NotImplementedException();
}
}
Then this code should give you what you want:
List<Foo> x = GetFirstList() ;
List<Foo> y = GetSecondList() ;
List<Foo> xNotInY = x.Where( xItem => ! y.Any( yItem => xItem.Equals(yItem) ) ).ToList() ;
You should bear in mind that this runs in O(N2) time. Consequently, you might want to implement an IEqualityComparer<Foo> and put your second list in a HashSet<Foo>:
class FooComparer : IEqualityComparer<Foo>
{
public bool Equals(Foo x, Foo y)
{
if ( x == null )
{
return y == null ;
}
else if ( y == null ) return false ;
else
{
return x.Equals(y) ;
}
}
public int GetHashCode(Foo obj)
{
return obj.GetHashCode() ;
}
}
Then do something like
List<Foo> x = GetFirstList() ;
List<Foo> y = GetSecondList() ;
HashSet<Foo> yLookup = new HashSet<Foo>( y , new FooComparer() ) ;
List<Foo> xNotInY = x.Where( x => !yLookup.Contains(x) ) ;
You'll incur some overhead in constructing the hash set (1 pass through the second list), but subsequent lookups via Contains() are O(1).
If you look at the sources for the Linq join operation, this is close to what it does.
It wouldn't be difficult to strip the Linq sources for Join() and it's helpers and tweak them to product left and right join operators instead of the stock inner join.
Does this work for your purposes?
var missing = List1.Except(List2);
If you need custom comparison logic you can build a custom IEqualityComparer. Note however that Except treats both lists as sets, so it will eliminate duplicates from List1.

Categories