Handling (2 raise to n) -1 conditions - c#

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.

Related

How to check the property elementAt() has a value and its not null

Sometimes the elements that I am checking against do not exist and the application throws an error.
if(responseSerialNumber.ElementAt(1) == 0)
{
//Do the following
}
How can I do deal with this?
There are 2 ways of solving this problem.
First, just check if the array has enough elements before accessing:
if(responseSerialNumber.Length > 2 && responseSerialNumber.ElementAt(1) == 0)
{
//Do the following
}
The second way is to use ElementAtOrDefault() which returns the appropriate default value based on the type of the array.
var item = responseSerialNumber.ElementAtOrDefault(1);
if (item != default(byte)) { // or use "(item != null)" if item is an reference type
//Do the following
}
BEWARE: The second solution would work fine if you have an array of non-value types (in this case they can have null as default value). If you have byte array, stick with the first solution.
If responseSerialNumber is an array byte[] (see comments) you can check the array: first for its Length then for the value
if (responseSerialNumber.Length >= 2 && responseSerialNumber[1] == 0) {
...
}
Or (for arbitrary indexAt and valueToTest):
if (responseSerialNumber.Length >= indexAt + 1 &&
responseSerialNumber[indexAt] == valueToTest) {
...
}
In general case (when responseSerialNumber is IEnumerable<T>) for given
int indexAt = 1;
valueToTest = 0;
we can Skip indexAt items and check the very next one:
if (responseSerialNumber.Skip(indexAt).Take(1).Any(item => item == valueToTest)) {
// responseSerialNumber has at least indexAt items
// indexAt's items is equal to valueToTest
}
Or even
if (responseSerialNumber.Where(index, value) =>
index == indexAt && value == valueToTest)) {
...
}

While loop multiple condition check with single variable

I am wondering if there is a way to check multiple while loop conditions using the same variable. That's a bit vague, but this example should clear it up:
while (myFunction(x) == 0 || myFunction(x) == 13639 || myFunction(x) == -4261.9583)
{ x++; }
Is it possible to only evaluate myFunction(x) once per loop while checking the three conditions, so that the function doesn't have to run three separate times for a result that is the same each time?
I am doing this for optimization/efficiency purposes. myFunction() could be a pretty time-consuming function, so I want it to run the minimum amount of times necessary.
Typically I would define the value of myFunction(x) before I start the while loop, but in this case, the value of myFunction(x) will be changing as the loop goes through each iteration, since the value of x will be changing.
Yes, this can be done:
double result;
while ((result = myFunction(x)) == 0 || result == 13639 || result == -4261.9583)
{ x++; }
Three options:
Do it backwards
Check a list for the result rather than checking the result against the list.
var list = new float[] { 0F, 13639F, -4261.9583F );
while (list.Contains(myFunction(x))
{
x++;
}
Write a function
Extracting the logic to another function is always a nice way to break down the problem.
bool IsValid(float input)
{
var result = myFunction(input);
return (result == 0 || result == 13639 || result == -4261.9583);
}
while (IsValid(x))
{
x++;
}
Use while(true)
Whenver the condition of a while loop is complicated, a common option is to remove the check from the () and put it in the {} instead. When you do this, use while (true).
while (true)
{
var result = myFunction(x);
if (result != 0 && result != 13639 && result != -4261.9583) break;
x++;
}
You can do this simply by moving the check into a separate method, which takes the return value of the function as parameter, and then performs the 3 checks on the value directly and returns a boolean accordingly.
Assuming the function returns a int typed value this may for example look something like this:
bool CheckResultValue(int value) {
return value == 0 || value == 13639 || value == -4261.9583;
}
Then your while loop could look something like this:
while (CheckResultValue(myFunction(x)))
{ x++; }

Identify number of conditions in a dynamic LINQ expression

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.

What does the bracket in this expression mean

I am modifying another developer's code and I don't know what the [0] bracket following the string means in this context, can someone explain to me? My first thought is it is referring to the first column of GridView1 but that isn't the correct way to designate a column is it? BTW the string values in the if statement are 7 digit numbers expressed as strings. The first column is the DataKey column.
if (GridView1.SelectedValue.ToString()[0] != '5' && GridView1.SelectedValue.ToString().Substring(0, 2) != "95")
{
LinkButton1.Visible = false;
LinkButton2.Visible = false;
}
else
{
LinkButton1.Visible = true;
LinkButton2.Visible = true;
}
String Accessing Individual Characters
You can use array notation with an index value to acquire read-only
access to individual characters
if (GridView1.SelectedValue.ToString()[0] != '5' && GridView1.SelectedValue.ToString().Substring(0, 2) != "95")
As noted in the comments, both the below will throw if there are not enough characters
GridView1.SelectedValue.ToString()[0]
GridView1.SelectedValue.ToString().Substring(0, 2)
Also as per DRY calling this twice is redundant and also messy
GridView1.SelectedValue.ToString()
When you can
var something = GridView1.SelectedValue.ToString();
Lastly, normally you would check this for sanity sake, Like
if(!string.IsNullOrEmpty(something) && something.Length >= 2)
if (something[0] != '5' && something.Substring(0, 2) != "95")
Anyway, have fun stringing

How to check if two string are of the same length?

I want to check if two string are of the same length. I tried the following, but it doesn't work.
string passnew = "1233";
string passcnfrm = "1234";
if((passnew.Length&&passcnfrm.Length)>6 ||(passnew.Length&&passcnfrm.Length)<15)
{
// ...
}
Why does it not work? What do I need to change?
if(passnew.Length == passcnfrm.Length &&
passnew.Length > 6 && passnew.Length < 15)
{
// do stuff
}
You are missing some basic syntax lessons. What you write inside of these brackets are conditions. We have unary operators (operating on one thing), binary operators (two) and one tertiary operator (forget about that one).
You cannot construct something like your "boundary test" with those easily.
A possible way:
(passnew.Length > 6) && (passcnfrm.Length > 6)
But you aren't testing if the length is equal anyway, even if you could use a syntax like that. You seem to want to compare if both are longer than 6 chars and shorter than 15 chars. One at 7 and one at 14 would satisfy both conditions..
if(passnew.Length == passcnfrm.Length &&
(passnew.Length < 15 && passnew.Length > 6))
{
// ...
}
Checks both are same length, and either one is more than 6 and less than 15 characters long.
that would be:
if(passcnfrm.Length.Equals(passnew.Length))
{
//do stuff
}
A probably better way to do it is:
if (( passnew != null && passcnfrm != null )
( passnew == passcnfrm )
&& ( passnew.Length > 6 && passnew.Length < 15 ))
{
// do stuff
}
Hides the length check inside the equality check which you'll probably need, it isn't in your question but the variable names make it pretty clear you're doing a password change function there. I added the null check to make sure the length checks don't throw a NullReferenceException, not needed in the example because you assign both manually, but might save some trouble if you're going to convert this to a method later on.
You can use like this:
if (s.Contains(s1[i]))
or:
boolean equalsIgnoreCase(String anotherString);
or use this method:
public static int occurrence(string [] a, string a2)
{
int occ = 0;
for (int i = 0; i < a.Length;i++ )
{
if(a[i].Equals(a2))
{
occ++;
}
}
return occ;
}

Categories

Resources