I've opted to implement the System.Linq.Dynamic namespace into my project where I rely on dynamically invoking LINQ expressions from a string against my underlying objects. This allows for highly configurable criteria at the data level.
string expression = "x.Client == 100 && x.Insurers.Any(it == 2 || it == 3)";
var x = new MyObject() { Client = 100, Insurers = new int[] { 1, 2 }};
var p = Expression.Parameter(typeof(MyObject), "x");
var e = System.Linq.Dynamic.DynamicExpression.ParseLambda(new[] { p }, null, expression);
bool result = e.Compile().DynamicInvoke(x); // True = condition met
My question is how do I dynamically identify the number of conditions each string expression contains so that I can give a weight to each expression and choose the one with the highest weight when overlapping occurs. Regex can work, but there must be something more efficient and practical such as an expression tree.
Ex.:
x.Client == 100 // Conditions = 1
x.Client == 100 && x.Insurers.Any(it == 3) // Conditions = 2
x.Client == 100 && x.Insurers.Any(it == 2 || it == 3) // Conditions = 3
I'm not familiar with the System.Linq.Dynamic library, but assuming it produces normal, strongly typed Expression trees you can use an ExpressionVisitor.
This one counts the number of boolean logical operations like &&:
int CountConditions(Expression expr)
{
var visitor = new CountBinaryOpsVisitor();
visitor.Visit(expr);
return visitor.BinaryOperationCount + 1;
}
class CountBinaryOpsVisitor : ExpressionVisitor
{
public int BinaryOperationCount { get; private set; }
protected override Expression VisitBinary(BinaryExpression node)
{
switch (node.NodeType)
{
case ExpressionType.And:
case ExpressionType.AndAlso:
case ExpressionType.Or:
case ExpressionType.OrElse:
case ExpressionType.ExclusiveOr:
// Don't count bitwise integer operations, if they are even supported?
if (node.Left.Type == typeof(bool))
BinaryOperationCount++;
break;
}
return base.VisitBinary(node);
}
}
An alternative approach would be to count the number of comparison operators (==, >= etc.), but I think that would need more complex code to handle boolean expressions like x.BooleanProp or x.Insurers.Any().
This implementation doesn't currently count conditional expressions (x ? y : z). Not sure how you would factor those into the number of conditions, especially when nested.
Related
Using a CSharpSyntaxRewriter I'd like to determine if a a particular BinaryExpression is an Artihmetic expression. Is there a simpler way to determine this than to code snippet below.
private static bool IsArithmeticOperator(BinaryExpressionSyntax node)
{
return node.IsKind(SyntaxKind.AddExpression) ||
node.IsKind(SyntaxKind.MultiplyExpression) ||
node.IsKind(SyntaxKind.DivideExpression) ||
node.IsKind(SyntaxKind.SubtractExpression) ||
node.IsKind(SyntaxKind.ModuloExpression);
}
Just feels a little clunky.
I am not sure this is possible, but there is something in the enum that maybe can help you,
the arithmetic expression are in order inside the enum SyntaxKind except ModuloExpression which you can check separately.
maybe other SyntaxKind in this range will also be good for your needs.
AddExpression = 307,
SubtractExpression = 308,
MultiplyExpression = 309,
DivideExpression = 310,
IntegerDivideExpression = 311,
ExponentiateExpression = 314,
LeftShiftExpression = 315,
RightShiftExpression = 316,
ConcatenateExpression = 317,
ModuloExpression = 318,
So you can do something like this :
private static bool IsArithmeticOperator(BinaryExpressionSyntax node)
{
SyntaxKind expressionKind = node.Kind();
return (expressionKind >= SyntaxKind.AddExpression && expressionKind <= SyntaxKind.DivideExpression)
|| expressionKind == SyntaxKind.ModuloExpression;
}
Update
This will work only for Microsoft.CodeAnalysis.VisualBasic
and wont work for Microsoft.CodeAnalysis.CSharp
I have 2 sets of 3 conditions each.
Let a,b,c be one set of conditions and x,y,z be the other set. I need to evaluate the following
if(a && x)
.....
else if(a && y)
.....
else if(a && z)
.....
In the same way 3 conditions with b and 3 with c.
What is the best way to evaluate the conditions without writing all the combinations?
Update :
I am making a game in Unity. The conditions a,b,c check whether the x position of the player is within a certain range compared to a ball's position and conditions x,y,z do the same for y position. Based on the correct condition(from the combination ax,ay,az,bx,by,bz,cx,cy,cz) one animation state(out of 9) is selected. So each condition would produce a different result.
Update :
I ended up making two functions that evaluate the two sets of conditions and each returns an enum on which bitwise OR is done to get the final state.
My first thought would be to at least test the first group of conditions first, and then test the second group of conditions afterwards. While this is not an answer that avoids writing all nine if statements, you will on average reduce the amount of if statements being checked.
if (a)
{
if (x) { }
else if (y) { }
else if (z) { }
}
else if (b)
{
if (x) { }
else if (y) { }
else if (z) { }
}
else if (c)
{
if (x) { }
else if (y) { }
else if (z) { }
}
Generate all possible combinations. Since you deal with Booleans, each gives you 2 options. Then the simplest possible combination of 2 bools results to 2 x 2 = 4 combinations. Generally saying, K = 2^n, where n represent number of booleans you deal with.
Would I be you, I would stick to Tuple<bool, bool, bool> and nested for(var i = 0; i < 2; i++) cycles (for n parameters n cycles needed).
Then I would feed a list of Tuple<Predicate<Tuple<bool, bool, bool>>, Action> which pairs predicate with callback that should trigger when predicates equals true.
Rest could be achieved with Linq. Something alike possibleCombinationsList.Select(tripleOfBooleans => predicatesAndCallbacksList.Single(predicateAndCallback => predicateAndCallback.Item1(tripleOfBooleans) == true)).Sinle().Item2();
Have fun.
This is one way of doing it using Linq expressions, Linq expressions is a way to define expressions dynamically where you can do multiple operations on them. i used here a fake conditional expression that takes a number as an argument just for the sake of demonstration. first define each condition in a method or directly within you code. then put all those into arrays, each conditions set to an array. then two foreach that executes the expressions.
int num = 20;
ConditionalExpression[] firstSet = { ExpressionA(num), ExpressionB(num), ExpressionC(num) };
ConditionalExpression[] secondSet = { ExpressionX(num), ExpressionY(num), ExpressionZ(num) };
foreach(var firstSetExpression in firstSet)
foreach (var secondSetExpression in secondSet)
{
var result1 = Expression.Lambda<Func<bool>>(firstSetExpression.Test).Compile();
var result2 = Expression.Lambda<Func<bool>>(secondSetExpression.Test).Compile();
if (result1.Invoke() && result2.Invoke())
{
// do your thing here
}
}
Where you define expressions for each condition within a method, for example like this:
private static ConditionalExpression ExpressionA(int num)
{
return Expression.Condition(
Expression.Constant(num > 10),
Expression.Constant("num is greater than 10"),
Expression.Constant("num is smaller than 10")
);
}
this can be even optimized in many ways, but only to get you started.
Update: This is another way for who dont like to compile at runtime. using delegates:
Func<int, bool>[] firstSet = new Func<int,bool> [] { ExpressionA(), ExpressionA(), ExpressionA() };
Func<int, bool>[] secondSet = new Func<int, bool>[] { ExpressionA(), ExpressionA(), ExpressionA() };
foreach(var firstSetExpression in firstSet)
foreach (var secondSetExpression in secondSet)
{
if (firstSetExpression.Invoke(20) && secondSetExpression.Invoke(20))
{
// do your thing here
}
}
...
...
...
private static Func<int, bool> ExpressionA()
{
return (x) => x > 10;
}
Good Luck.
I have the following code
int someCount = 0;
for ( int i =0 ; i < intarr.Length;i++ )
{
if ( intarr[i] % 2 == 0 )
{
someCount++;
continue;
}
// Some other logic for those not satisfying the condition
}
Is it possible to use any of the Array.Where or Array.SkiplWhile to achieve the same?
foreach(int i in intarr.where(<<condtion>> + increment for failures) )
{
// Some other logic for those not satisfying the condition
}
Use LINQ:
int someCount = intarr.Count(val => val % 2 == 0);
I definitely prefer #nneonneo's way for short statements (and it uses an explicit lambda), but if you want to build a more elaborate query, you can use the LINQ query syntax:
var count = ( from val in intarr
where val % 2 == 0
select val ).Count();
Obviously this is probably a poor choice when the query can be expressed with a single lambda expression, but I find it useful when composing larger queries.
More examples: http://code.msdn.microsoft.com/101-LINQ-Samples-3fb9811b
Nothing (much) prevents you from rolling your own Where that counts the failures. "Nothing much" because neither lambdas nor methods with yield return statements are allowed to reference out/ref parameters, so the desired extension with the following signature won't work:
// dead-end/bad signature, do not attempt
IEnumerable<T> Where(
this IEnumerable<T> self,
Func<T,bool> predicate,
out int failures)
However, we can declare a local variable for the failure-count and return a Func<int> that can get the failure-count, and a local variable is completely valid to reference from lambdas. Thus, here's a possible (tested) implementation:
public static class EnumerableExtensions
{
public static IEnumerable<T> Where<T>(
this IEnumerable<T> self,
Func<T,bool> predicate,
out Func<int> getFailureCount)
{
if (self == null) throw new ArgumentNullException("self");
if (predicate == null) throw new ArgumentNullException("predicate");
int failures = 0;
getFailureCount = () => failures;
return self.Where(i =>
{
bool res = predicate(i);
if (!res)
{
++failures;
}
return res;
});
}
}
...and here's some test code that exercises it:
Func<int> getFailureCount;
int[] items = { 0, 1, 2, 3, 4 };
foreach(int i in items.Where(i => i % 2 == 0, out getFailureCount))
{
Console.WriteLine(i);
}
Console.WriteLine("Failures = " + getFailureCount());
The above test, when run outputs:
0
2
4
Failures = 2
There are a couple caveats I feel obligated to warn about. Since you could break out of the loop prematurely without having walked the entire IEnumerable<>, the failure-count would only reflect encountered-failures, not the total number of failures as in #nneonneo's solution (which I prefer.) Also, if the implementation of LINQ's Where extension were to change in a way that called the predicate more than once per item, then the failure count would be incorrect. One more point of interest is that, from within your loop body you should be able to make calls to the getFailureCount Func to get the current running failure count so-far.
I presented this solution to show that we are not locked-into the existing prepackaged solutions. The language and framework provides us with lots of opportunities to extend it to suit our needs.
I have the following class:
public class Test
{
public string Text { get; set; }
public int Number { get; set; }
}
And I'm creating and Expression tree of type Expression<Func<Test, bool>> on this class. When I do it like this:
Expression<Func<Test, bool>> predicate1 = x => x.Text.Length > 5 && x.Number > 0;
I get the following debug view:
.Lambda #Lambda1<System.Func`2[NHLinqTest.Test,System.Boolean]>(NHLinqTest.Test $x) {
($x.Text).Length > 5 && $x.Number > 0
}
note: there's a && for and-operation.
When I do it like this:
var y = Expression.Parameter(typeof(Test));
var predicate2 = Expression.And(
Expression.GreaterThan(
Expression.Property(Expression.Property(y, "Text"), "Length"),
Expression.Constant(5)),
Expression.GreaterThan(
Expression.Property(y, "Number"),
Expression.Constant(0)));
I get the following debug view:
($var1.Text).Length > 5 & $var1.Number > 0
Note: there's & for and-operation. Why do I get & in the second case? How to modify predicate2 to get && instead of &?
Thanks in advance!
Because it is & - i.e. bitwise / non-short-circuiting "and". For && you want Expression.AndAlso.
See also Expression.Or (|) vs Expression.OrElse (||).
Also, note that Expression != C# - it is language independent, so you might also see some cases where you don't get back (visually) what you would expect from C#.
Compare Expression.And:
Creates a BinaryExpression that represents a bitwise AND operation.
and Expression.AndAlso:
Creates a BinaryExpression that represents a conditional AND operation that evaluates the second operand only if the first operand evaluates to true.
And then compare that to your knowledge of the & and && operators.
The "&" operator and Expression.And represent a bitwise and. The "&&" operator and Expression.AndAlso represent a logical (and short-cutting) and operator.
I have one logical question. I have collection of employee objects
There are 3 filter criteria conditions which have handle
For e.g. Employee name, Office name, salary.
Now these filter criteria should match like (Employee name AND/OR Office name AND/OR salary)
So here I have to write (2 raise n) -1 if conditions to handle this situation.
Is there any other way we can do this.
For (Employee name AND/OR Office name) condition I m doing following
if (criteria.EmpName != "" && criteria.OfficeName != "")
{
if (emp.EmpName == criteria.EmpName && emp.OfficeName == criteria.OfficeName)
{
bIsMatch = true;
}
}
else
{
if (criteria.EmpName != "" && emp.EmpName == criteria.EmpName)
bIsMatch = true;
else if (criteria.OfficeName != "" && emp.OfficeName == criteria.OfficeName)
bIsMatch = true;
}
Now if have to handle saraly also i have write min 5 conditions.
Is thr other way to do it?
There are lots of ways to do it, but since you didn't specify one specific language and since I don't feel qualified to judge your coding style, here's one that keeps the general form of your code, while demonstrating some better logic:
bool bIsMatch = true;
if (criteria.EmpName != "" && criteria.EmpName != emp.EmpName) {
bIsMatch = false;
} else if (criteria.OfficeName != "" && criteria.OffIceName != emp.OfficeName) {
bIsMatch = false;
} /* Repeat for as many conditions as there are */
if (bIsMatch) {
/* None of the checks above failed */
}
You can pair up your filtering conditions and have a single statement that encodes all the parameters:
if( (criteria.EmpName.equals("") || criteria.EmpName.equals(emp.EmpName))
&& (criteria.OfficeName.equals("") || criteria.OfficeName.equals(emp.OfficeName))
&& (criteria.Salary.equals("") || criteria.Salary.equals(emp.Salary)))
In each of the AND-ed expressions checks first if the filter is empty, if it is that piece will result in true, if it's not, then the check is performed against the corresponding value in emp and is true only when that check is true.
Start out by assuming you have a match and Then apply each criterion one by one.
bIsMatch = true;
if (bIsMatch && criteria.EmpName != "") bIsMatch = emp.EmpName == criteria.EmpName;
if (bIsMatch && criteria.OfficeName != "") bIsMatch = emp.OfficeName == criteria.OfficeName;
// ...
Or, write a helper function that does the matching.
bool IsMatch(String criterion, String value)
{
return criterion == "" || criterion == value;
}
Then you can do everything in one big if statement:
if (IsMatch(criteria.EmpName, emp.EmpName) &&
IsMatch(criteria.OfficeName, emp.OfficeName) &&
...
)
You can check the criteria individually and maintain a count of matches. That way you need only n conditions:
int matches = 0;
if (criteria.EmpName != "" && emp.EmpName == criteria.EmpName)
matches++;
// similar code for other criteria
if (matches >= 2) { // as many matches as required
// succeeded
}
How about this? The idea scales well for more filters, except that the mapping itself is convention based (name - name).
var map = new Dictionary<string, string>
{
{ criteria.EmpName, emp.EmpName },
{ criteria.OfficeName, emp.OfficeName},
{ criteria.ThirdProp, emp.ThirdProp }
};
bIsMatch = dict.All(kvp => string.IsNullOrEmpty(kvp.Key) || kvp.Key == kvp.Value);
I would question the overall design though; there's something that doesn't seem right about it. How would you deal with the Salary field that you mention? Surely, that's not a string? What's the sentinel-value being used in that case?
Make sure you are clear enough about the business logic before writing the code. According to your code, I can see that you want to check if emp and criteria have the same EmployeeName and OfficeName, any of the properties is considered to be the same if it's string.Empty. The code will be quite clear after yourself is clear. Here we go:
public static bool EmptyOrEquals(this string one, string another)
{
return string.IsNullOrEmpty(another) || one.Equals(another);
}
bIsMatch = emp.EmpName.EmptyOrEquals(criteria.EmpName)
&& emp.OfficeName.EmptyOrEquals(criteria.OfficeName);
Test each question individually and use a bit set to encode the combinations of answers.
This results in cleaner code because you only test each criteria once, it's compact yet readable, and yet you can easily plug in code to handle each combination. And it's the fast too. O(n) to test all the criteria and O(1) to find the actual combination.
For a small, fixed number of criteria, you can push bits around manually. For many criteria, or for a solution that scales, use java.util.BitSet
Bit pushing example:
int bits = 0;
if (...criteria 1...) {
bits = 1;
}
if (...criteria 2...) {
bits |= 2;
}
if (...bits 3...) {
bits |= 4;
}
switch (bits) {
case 0: // no criteria matched
;
case 1: // criteria 1 matched
;
case 2: // criteria 2 matched
;
case 3: // criteria 1 AND 2 matched
;
case 4: // criteria 3 matched
;
case 5: // criteria 1 AND 3 matched
;
case 6: // criteria 2 AND 3 matched
;
case 7: // criteria 1 AND 2 AND 3 matched
;
}
You can generalize this solution using java.util.BitSet to manipulate bits for n criteria (useful when n > 64!). To facilitate quick look up, store the hash of each BitSet combination in a map that maps the hash code to a command class.