How to Combine two lambdas
To complete Eric's answer, using the new ExpressionVisitor
introduced in .NET 4 rather than a custom rewriter:
internal class ParameterReplacer : ExpressionVisitor {
private readonly ParameterExpression _parameter;
protected override Expression VisitParameter(ParameterExpression node) {
return base.VisitParameter(_parameter);
}
internal ParameterReplacer(ParameterExpression parameter) {
_parameter = parameter;
}
}
class Program {
static void Main(string[] args) {
Expression<Func<string, bool>> expr1 = s => s.Length == 5;
Expression<Func<string, bool>> expr2 = s => s == "someString";
var paramExpr = Expression.Parameter(typeof(string));
var exprBody = Expression.Or(expr1.Body, expr2.Body);
exprBody = (BinaryExpression) new ParameterReplacer(paramExpr).Visit(exprBody);
var finalExpr = Expression.Lambda<Func<string, bool>>(exprBody, paramExpr);
}
}
How can I combine two lambda expressions without using Invoke method?
The problem is that you can't just "and"/"or" them, because you need to re-write the internals to change the parameters; if you use the .Body
from e1
, but the parameter from e2
, it won't work - because the .Body
of e1
references a completely unrelated parameter instance that isn't defined. This is more obvious if you use:
Expression<Func<MyEntity, bool>> e1 = i => i.FName.Contains("john");
Expression<Func<MyEntity, bool>> e2 = j => j.LName.Contains("smith");
(note the difference between e1
using i
and e2
using j
)
If we combine them without rewriting the parameter, we would get the nonsensical:
Expression<Func<MyEntity, bool>> combined =
i => i.FName.Contains("john") && j.LName.Contains("smith");
(woah.... where did j
come from?)
HOWEVER; the problem is identical regardless of the name of the parameter: it is still a different parameter.
And since the expression is immutable you can't just swap it "in place".
The trick is to use a "visitor" to rewrite the nodes, like so:
using System;
using System.Linq.Expressions;
class SwapVisitor : ExpressionVisitor
{
private readonly Expression from, to;
public SwapVisitor(Expression from, Expression to)
{
this.from = from;
this.to = to;
}
public override Expression Visit(Expression node)
{
return node == from ? to : base.Visit(node);
}
}
static class Program
{
static void Main()
{
Expression<Func<MyEntity, bool>> e1 = i => i.FName.Contains("john");
Expression<Func<MyEntity, bool>> e2 = i => i.LName.Contains("smith");
// rewrite e1, using the parameter from e2; "&&"
var lambda1 = Expression.Lambda<Func<MyEntity, bool>>(Expression.AndAlso(
new SwapVisitor(e1.Parameters[0], e2.Parameters[0]).Visit(e1.Body),
e2.Body), e2.Parameters);
// rewrite e1, using the parameter from e2; "||"
var lambda2 = Expression.Lambda<Func<MyEntity, bool>>(Expression.OrElse(
new SwapVisitor(e1.Parameters[0], e2.Parameters[0]).Visit(e1.Body),
e2.Body), e2.Parameters);
}
}
Typescript how to combine two lambda expressions
I like the question... here is a full example, after which a quick explanation:
class Example {
constructor(
public num: number,
public bool: boolean
) {}
}
var examples: Example[] = [
new Example(5, true),
new Example(5, false),
new Example(6, true),
];
function exampleFilter(arr: Example[], predicate: (x: Example) => boolean) {
var matches: Example[] = [];
for (var i = 0; i < arr.length; i++) {
if (predicate(arr[i])) {
matches.push(arr[i]);
}
}
return matches;
}
function exampleFilter2(arr: Example[], predicate: (x: Example) => boolean) {
var newPredicate = function(x: Example) {
return x.bool && predicate(x);
}
var matches: Example[] = [];
for (var i = 0; i < arr.length; i++) {
if (newPredicate(arr[i])) {
matches.push(arr[i]);
}
}
return matches;
}
var a = exampleFilter(examples, (x) => x.num < 6);
console.log(a);
var b = exampleFilter2(examples, (x) => x.num < 6);
console.log(b);
So the difference between exampleFilter
and exampleFilter2
is the extension of the predicate, which is done like this:
var newPredicate = function(x: Example) {
return x.bool && predicate(x);
}
So this is the technique you can employ to make a refinable item as you describe in your question.
Query Class
Here is a basic example of a class that will act as a generic query over an array of type T.
class Query<T> {
constructor(private arr: T[], private predicate: (x:T) => boolean) {}
and(predicate: (x:T) => boolean) {
var priorCondition = this.predicate;
this.predicate = (x:T) => {
return priorCondition(x) && predicate(x);
}
return this;
}
toList() {
var matches: T[] = [];
for (var i = 0; i < this.arr.length; i++) {
if (this.predicate(this.arr[i])) {
matches.push(this.arr[i]);
}
}
return matches;
}
}
The and
method simply merges each predicate it is passed.
var q = new Query(examples, (x) => x.num < 6);
q.and((x) => x.bool);
var result = q.toList();
Or even:
var result = new Query(examples, (x) => x.num < 6).and((x) => x.bool).toList();
Caution
Beware of one mistake I have seen a few times in this zone... we have an API now that looks a bit like Linq and acts a bit like Linq - but you'll need to use ECMAScript 6 generators if you want to actually work like Linq.
Combine two and more lambda functions into one
A direct answer to your question is the following (with a minor optimization to move the date comparison with startdate
out of the lambda function).
df_to_update = df[df.DATE_G > startdate].apply(
lambda x: (df.loc[
(
(df.DATE_G < x.DATE_G)
& (df.DATE_G >= (x.DATE_G + pd.DateOffset(days=-730)))
& (df.ID1_G == x.ID1_G)
& (df.ID_C_T == x.ID_C_T)
),
["RES", "S1"],
].mean()),
axis=1,
)
df_to_update.columns = ["RES1_2Y", "C1_2Y"]
df.update(df_to_update)
combine multiple lambda expressions with different types to one expression
Fortunately, I solved the problem.
The final result here is for others if they encounter such a problem.
public static Expression<Func<B, bool>> Combine<B, A>(this Expression<Func<B, bool>> expr1, Expression<Func<A, bool>> expr2, Expression<Func<B, A>> property)
{
// this is (q) parameter of my property
var replaceParameter = property.Parameters[0];
// replacing all (b) parameter with the (q)
// these two lines converts `b => b.Id == 100` to `q => q.Id == 100`
// using ReplaceExpVisitor class
var leftVisitor = new ReplaceExpVisitor(replaceParameter);
var left = leftVisitor.Visit(expr1.Body);
// the property body is 'q.objectA'
var replaceBody = property.Body;
// now i'm replacing every (a) parameter of my second expression to 'q.objectA'
// these two lines convert this statement:
// a.Id > 1 && a.address.city == "city1" || a.address.country == "us"
// to this :
// q.objectA.Id > 1 && q.objectA.address.city == "city1" || q.objectA.address.country == "us"
var rightVisitor = new ReplaceExpVisitor(replaceBody);
var right = rightVisitor.Visit(expr2.Body);
// creating new expression and pass (q) reference to it (replaceParameter).
return Expression.Lambda<Func<B, bool>>(Expression.AndAlso(left, right), replaceParameter);
}
// this is a simple class to replace all parameters with new expression
private class ReplaceExpVisitor : ExpressionVisitor
{
private readonly Expression _newval;
public ReplaceExpVisitor(Expression newval) => _newval = newval;
protected override Expression VisitParameter(ParameterExpression node)
{
return _newval;
}
}
usage :
var result = classBRule.Combine(classARule, q => q.objectA);
// or
Expression<Func<ClassB,bool>> result =
Combine<ClassB, ClassA>(classBRule, classARule, q => q.objectA);
/*
result is equal to the expected expression in the first example now
result output :
q =>
((q.Id == 100) &&
(((q.objectA.Id > 1) && (q.objectA.address.city == "city1")) ||
(q.objectA.address.country == "us")))
*/
https://dotnetfiddle.net/KnV3Dz
Combine two lambda expressions with inner expression
The ParameterReplacer you have used is too simplified and blindly replaces every parameter.
Use this instead:
public static class ExpressionUtils
{
public static Expression ReplaceParameter(this Expression expression, ParameterExpression source, Expression target)
{
return new ParameterReplacer { Source = source, Target = target }.Visit(expression);
}
class ParameterReplacer : ExpressionVisitor
{
public ParameterExpression Source;
public Expression Target;
protected override Expression VisitParameter(ParameterExpression node)
{
return node == Source ? Target : base.VisitParameter(node);
}
}
}
Or use this or this predicate builder helpers.
Combining two lambda expressions in c#
OK; pretty long snippet, but here's a starter for an expression-rewriter; it doesn't handle a few cases yet (I'll fix it later), but it works for the example given and a lot of others:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text.RegularExpressions;
public class GrandParent
{
public Parent Parent { get; set; }
}
public class Parent
{
public Child Child { get; set; }
public string Method(string s) { return s + "abc"; }
}
public class Child
{
public string Name { get; set; }
}
public static class ExpressionUtils
{
public static Expression<Func<T1, T3>> Combine<T1, T2, T3>(
this Expression<Func<T1, T2>> outer, Expression<Func<T2, T3>> inner, bool inline)
{
var invoke = Expression.Invoke(inner, outer.Body);
Expression body = inline ? new ExpressionRewriter().AutoInline(invoke) : invoke;
return Expression.Lambda<Func<T1, T3>>(body, outer.Parameters);
}
}
public class ExpressionRewriter
{
internal Expression AutoInline(InvocationExpression expression)
{
isLocked = true;
if(expression == null) throw new ArgumentNullException("expression");
LambdaExpression lambda = (LambdaExpression)expression.Expression;
ExpressionRewriter childScope = new ExpressionRewriter(this);
var lambdaParams = lambda.Parameters;
var invokeArgs = expression.Arguments;
if (lambdaParams.Count != invokeArgs.Count) throw new InvalidOperationException("Lambda/invoke mismatch");
for(int i = 0 ; i < lambdaParams.Count; i++) {
childScope.Subst(lambdaParams[i], invokeArgs[i]);
}
return childScope.Apply(lambda.Body);
}
public ExpressionRewriter()
{
subst = new Dictionary<Expression, Expression>();
}
private ExpressionRewriter(ExpressionRewriter parent)
{
if (parent == null) throw new ArgumentNullException("parent");
subst = new Dictionary<Expression, Expression>(parent.subst);
inline = parent.inline;
}
private bool isLocked, inline;
private readonly Dictionary<Expression, Expression> subst;
private void CheckLocked() {
if(isLocked) throw new InvalidOperationException(
"You cannot alter the rewriter after Apply has been called");
}
public ExpressionRewriter Subst(Expression from,
Expression to)
{
CheckLocked();
subst.Add(from, to);
return this;
}
public ExpressionRewriter Inline() {
CheckLocked();
inline = true;
return this;
}
public Expression Apply(Expression expression)
{
isLocked = true;
return Walk(expression) ?? expression;
}
private static IEnumerable<Expression> CoalesceTerms(
IEnumerable<Expression> sourceWithNulls, IEnumerable<Expression> replacements)
{
if(sourceWithNulls != null && replacements != null) {
using(var left = sourceWithNulls.GetEnumerator())
using (var right = replacements.GetEnumerator())
{
while (left.MoveNext() && right.MoveNext())
{
yield return left.Current ?? right.Current;
}
}
}
}
private Expression[] Walk(IEnumerable<Expression> expressions) {
if(expressions == null) return null;
return expressions.Select(expr => Walk(expr)).ToArray();
}
private static bool HasValue(Expression[] expressions)
{
return expressions != null && expressions.Any(expr => expr != null);
}
// returns null if no need to rewrite that branch, otherwise
// returns a re-written branch
private Expression Walk(Expression expression)
{
if (expression == null) return null;
Expression tmp;
if (subst.TryGetValue(expression, out tmp)) return tmp;
switch(expression.NodeType) {
case ExpressionType.Constant:
case ExpressionType.Parameter:
{
return expression; // never a need to rewrite if not already matched
}
case ExpressionType.MemberAccess:
{
MemberExpression me = (MemberExpression)expression;
Expression target = Walk(me.Expression);
return target == null ? null : Expression.MakeMemberAccess(target, me.Member);
}
case ExpressionType.Add:
case ExpressionType.Divide:
case ExpressionType.Multiply:
case ExpressionType.Subtract:
case ExpressionType.AddChecked:
case ExpressionType.MultiplyChecked:
case ExpressionType.SubtractChecked:
case ExpressionType.And:
case ExpressionType.Or:
case ExpressionType.ExclusiveOr:
case ExpressionType.Equal:
case ExpressionType.NotEqual:
case ExpressionType.AndAlso:
case ExpressionType.OrElse:
case ExpressionType.Power:
case ExpressionType.Modulo:
case ExpressionType.GreaterThan:
case ExpressionType.GreaterThanOrEqual:
case ExpressionType.LessThan:
case ExpressionType.LessThanOrEqual:
case ExpressionType.LeftShift:
case ExpressionType.RightShift:
case ExpressionType.Coalesce:
case ExpressionType.ArrayIndex:
{
BinaryExpression binExp = (BinaryExpression)expression;
Expression left = Walk(binExp.Left), right = Walk(binExp.Right);
return (left == null && right == null) ? null : Expression.MakeBinary(
binExp.NodeType, left ?? binExp.Left, right ?? binExp.Right, binExp.IsLiftedToNull,
binExp.Method, binExp.Conversion);
}
case ExpressionType.Not:
case ExpressionType.UnaryPlus:
case ExpressionType.Negate:
case ExpressionType.NegateChecked:
case ExpressionType.Convert:
case ExpressionType.ConvertChecked:
case ExpressionType.TypeAs:
case ExpressionType.ArrayLength:
{
UnaryExpression unExp = (UnaryExpression)expression;
Expression operand = Walk(unExp.Operand);
return operand == null ? null : Expression.MakeUnary(unExp.NodeType, operand,
unExp.Type, unExp.Method);
}
case ExpressionType.Conditional:
{
ConditionalExpression ce = (ConditionalExpression)expression;
Expression test = Walk(ce.Test), ifTrue = Walk(ce.IfTrue), ifFalse = Walk(ce.IfFalse);
if (test == null && ifTrue == null && ifFalse == null) return null;
return Expression.Condition(test ?? ce.Test, ifTrue ?? ce.IfTrue, ifFalse ?? ce.IfFalse);
}
case ExpressionType.Call:
{
MethodCallExpression mce = (MethodCallExpression)expression;
Expression instance = Walk(mce.Object);
Expression[] args = Walk(mce.Arguments);
if (instance == null && !HasValue(args)) return null;
return Expression.Call(instance, mce.Method, CoalesceTerms(args, mce.Arguments));
}
case ExpressionType.TypeIs:
{
TypeBinaryExpression tbe = (TypeBinaryExpression)expression;
tmp = Walk(tbe.Expression);
return tmp == null ? null : Expression.TypeIs(tmp, tbe.TypeOperand);
}
case ExpressionType.New:
{
NewExpression ne = (NewExpression)expression;
Expression[] args = Walk(ne.Arguments);
if (HasValue(args)) return null;
return ne.Members == null ? Expression.New(ne.Constructor, CoalesceTerms(args, ne.Arguments))
: Expression.New(ne.Constructor, CoalesceTerms(args, ne.Arguments), ne.Members);
}
case ExpressionType.ListInit:
{
ListInitExpression lie = (ListInitExpression)expression;
NewExpression ctor = (NewExpression)Walk(lie.NewExpression);
var inits = lie.Initializers.Select(init => new
{
Original = init,
NewArgs = Walk(init.Arguments)
}).ToArray();
if (ctor == null && !inits.Any(init => HasValue(init.NewArgs))) return null;
ElementInit[] initArr = inits.Select(init => Expression.ElementInit(
init.Original.AddMethod, CoalesceTerms(init.NewArgs, init.Original.Arguments))).ToArray();
return Expression.ListInit(ctor ?? lie.NewExpression, initArr);
}
case ExpressionType.NewArrayBounds:
case ExpressionType.NewArrayInit:
/* not quite right... leave as not-implemented for now
{
NewArrayExpression nae = (NewArrayExpression)expression;
Expression[] expr = Walk(nae.Expressions);
if (!HasValue(expr)) return null;
return expression.NodeType == ExpressionType.NewArrayBounds
? Expression.NewArrayBounds(nae.Type, CoalesceTerms(expr, nae.Expressions))
: Expression.NewArrayInit(nae.Type, CoalesceTerms(expr, nae.Expressions));
}*/
case ExpressionType.Invoke:
case ExpressionType.Lambda:
case ExpressionType.MemberInit:
case ExpressionType.Quote:
throw new NotImplementedException("Not implemented: " + expression.NodeType);
default:
throw new NotSupportedException("Not supported: " + expression.NodeType);
}
}
}
static class Program
{
static void Main()
{
Expression<Func<GrandParent, Parent>> myFirst = gp => gp.Parent;
Expression<Func<Parent, string>> mySecond = p => p.Child.Name;
Expression<Func<GrandParent, string>> outputWithInline = myFirst.Combine(mySecond, false);
Expression<Func<GrandParent, string>> outputWithoutInline = myFirst.Combine(mySecond, true);
Expression<Func<GrandParent, string>> call =
ExpressionUtils.Combine<GrandParent, Parent, string>(
gp => gp.Parent, p => p.Method(p.Child.Name), true);
unchecked
{
Expression<Func<double, double>> mathUnchecked =
ExpressionUtils.Combine<double, double, double>(x => (x * x) + x, x => x - (x / x), true);
}
checked
{
Expression<Func<double, double>> mathChecked =
ExpressionUtils.Combine<double, double, double>(x => x - (x * x) , x => (x / x) + x, true);
}
Expression<Func<int,int>> bitwise =
ExpressionUtils.Combine<int, int, int>(x => (x & 0x01) | 0x03, x => x ^ 0xFF, true);
Expression<Func<int, bool>> logical =
ExpressionUtils.Combine<int, bool, bool>(x => x == 123, x => x != false, true);
Expression<Func<int[][], int>> arrayAccess =
ExpressionUtils.Combine<int[][], int[], int>(x => x[0], x => x[0], true);
Expression<Func<string, bool>> isTest =
ExpressionUtils.Combine<string,object,bool>(s=>s, s=> s is Regex, true);
Expression<Func<List<int>>> f = () => new List<int>(new int[] { 1, 1, 1 }.Length);
Expression<Func<string, Regex>> asTest =
ExpressionUtils.Combine<string, object, Regex>(s => s, s => s as Regex, true);
var initTest = ExpressionUtils.Combine<int, int[], List<int>>(i => new[] {i,i,i},
arr => new List<int>(arr.Length), true);
var anonAndListTest = ExpressionUtils.Combine<int, int, List<int>>(
i => new { age = i }.age, i => new List<int> {i, i}, true);
/*
var arrBoundsInit = ExpressionUtils.Combine<int, int[], int[]>(
i => new int[i], arr => new int[arr[0]] , true);
var arrInit = ExpressionUtils.Combine<int, int, int[]>(
i => i, i => new int[1] { i }, true);*/
}
}
Java utility method to combine two lambdas?
Are you talking about Java 8 lambdas? Because such utilities exist, for example:
Predicate<Foo> pred1 = f -> true;
Predicate<Foo> pred2 = pred1.and(f -> false);
or
Function<Int,Int> func1 = x -> x + 1;
Function<Int,Int> func2 = func1.andThen(x -> x*2);
You should take a look at java.util.function package because you will likely find the feature already available.
In your specific example you are not composing two functions, indeed, functionally speaking, you can't compose two functions that accept two arguments and return one argument (or void).
This because you are lacking a requirement: the codomain of the first function must correspond to the domain of the second function, otherwise composition can't be done.
What you are really doing here is sequentially calling two unrelated functions with same arguments. This problem can be solved by doing exactly the same thing:
BiConsumer<Foo,Bar> combination = (f,b) -> { doSomething(f,b); doSomethingElse(f,b); };
Related Topics
Memcached with Windows and .Net
Why How to Not Edit a Method That Contains an Anonymous Method in the Debugger
How to Translate Cultureinfo Language Names
Upgrading Old Unity Code to Unity 5
Rotate - Transposing a List<List<String>> Using Linq C#
"Movefile" Function in C# (Delete File After Reboot)
C#: Triggering an Event When an Object Is Added to a Queue
How to Perform an Insert and Return Inserted Identity with Dapper
How to Set Web.Config File to Show Full Error Message
How to Create a New Language for Use in Visual Studio
Record Video of Screen Using .Net Technologies
Xamarin Project Not Running, Assembly Not Found
Explicit Conversion Operator Error When Converting Generic Lists
When Should I Create a New Dbcontext()
Correct Way to Get the Coredispatcher in a Windows Store App