Checking valid combination of items in list - c#

I have a list of items that I need to validate. The list can contain any number of items of the type A, B and C, but before the list can be saved, it must confirm to the following rules:
If you have A, you need either B or C
If you have B, you need A
I have ended up with the following code (saudo code):
bool IsListValid()
{
var a = list.ContainsAny(A);
var b = list.ContainsAny(B);
var c = list.ContainsAny(C);
if (!a && !b)
return true;
if (a && (b || c)
return true;
return false;
}
I don't like this code.
1. The use of Any three times in a row will potentially iterate the list three times
2. The if's doesn't look good to me.
Of cause it would be better with different variable names and by extracting the test into methods with good names, but I think there are better ways of solving this entirely. I'm just not sure how...
Any tips?

I would use a simple loop, it's both, comprehensible and efficient.
bool containsA = false, containsB = false, containsC = false;
for (int i = 0; i < list.Count; i++)
{
Type itemType = list[i].GetType();
if (!containsA) containsA = itemType == typeof(A);
if (!containsB) containsB = itemType == typeof(B);
if (!containsC) containsC = itemType == typeof(C);
if (containsA && (containsB || containsC)) return true;
}
return (!containsA && !containsB);

If it's so important that you only go through the list once, you could do this:
bool a = false;
bool b = false;
bool c = false;
foreach(var x in list)
{
if (x is A) a = true;
if (x is B) b = true;
if (x is C) c = true;
}
But I'd leave it as it is. If profiling later shows that this code is becoming a bottleneck, you can revisit it then.
As for the if's, that looks fine to me. As long as A, B and C are properly named (something like hasNotifyEmail or needsResponse, something that explains why you want them to work with the specified rules) then it should be easy for others to understand.

var hasA = list.Any(x => x.GetType() == typeof(A));
var hasB = list.Any(x => x.GetType() == typeof(B));
var hasC = list.Any(x => x.GetType() == typeof(C));
//If you have A, you need either B or C
// A AND (B xor C)
if (hasA && (hasB ^= hasC))
return true;
//If you have B, you need A
if (hasB && hasA)
return true;
return false;

Related

Is there a faster way to compare these decimals?

I have a stream of decimals and I am trying to compare the most recent decimal to the difference of the last 6 decimals, I may increase this number
I have the following class
public class CompareRandom
{
private const decimal DIFFERENCE = 1.8m;
public decimal a;
public decimal b;
public decimal c;
public decimal d;
public decimal e;
public decimal f;
public decimal g;
public bool Compare(decimal num)
{
this.g = this.f;
this.f = this.e;
this.e = this.d;
this.d = this.c;
this.c = this.b;
this.b = this.a;
this.a = num;
if (b != decimal.Zero && b / DIFFERENCE > a)
{
return true;
}
if (c != decimal.Zero && c / DIFFERENCE > a)
{
return true;
}
if (d != decimal.Zero && d / DIFFERENCE > a)
{
return true;
}
if (e != decimal.Zero && e / DIFFERENCE > a)
{
return true;
}
if (f != decimal.Zero && f / DIFFERENCE > a)
{
return true;
}
if (g != decimal.Zero && g / DIFFERENCE > a)
{
return true;
}
return false;
}
}
Then I initialize it as volatile
volatile static CompareRandom CompareRandom = new CompareRandom();
Then I call CompareRandom.Compare(value) synchronously as part of a loop that updates every 1ms to compare the values.
The part I am the most interested in knowing if there is a faster way to do is this part
this.g = this.f;
this.f = this.e;
this.e = this.d;
this.d = this.c;
this.c = this.b;
this.b = this.a;
this.a = num;
A successful answer will demonstrate a faster execution of the method Compare
See if you can make it faster:
https://dotnetfiddle.net/tLw8qM
https://dotnetfiddle.net/jd0bSF
You don't need to perform the division every time. Instead, multiply a by DIFFERENCE to obtain a threshold:
// Name changed to be more conventional
private const decimal Difference = 1.8m;
public bool Compare(decimal num)
{
g = f;
f = e;
e = d;
d = c;
c = b;
b = a;
a = num;
var threshold = num * Difference;
return (b != decimal.Zero && b > threshold) ||
(c != decimal.Zero && c > threshold) ||
(d != decimal.Zero && d > threshold) ||
(e != decimal.Zero && e > threshold) ||
(f != decimal.Zero && f > threshold) ||
(g != decimal.Zero && g > threshold);
};
As asides:
It's odd for a Compare method to return bool rather than an integer; given that it's not the "common" meaning of Compare, it's probably worth renaming it for clarity
It's very odd for a comparison method to change the state of an object, as this is doing (assigning to a) - another good reason to change the name.
Using a collection instead of separate variables would make all of this more maintainable, but I'd be surprised if it improved the speed.
I also really like the idea of eliminating the division, but I don't like the way you're handling booleans: the original question says something like:
if condition1 then return true;
if condition2 then return true;
if condition3 then return true;
If condition1 is true, then the code does not bother about the calculation of the other conditions (why would it, when one condition is true, then the OR of all conditions also is true).
The proposal from Jon looks as follows:
return (condition1 || condition2 || condition3)
This does exactly the same thing, but the fact if the calculation of the OR equation is determined by the compiler: if you're dealing with an older compiler, not performing optimsation, then the entire calculation is done, even if condition1 is true.

How can I write multiple IF conditions in IEnumarable

Please give me a hint what return type I mention:
public IEnumerable<EMS_BUSINESSTYPE_MASTER> CustomerType(int Cust)
{
if (Cust == 1)
{
var x = (from n in db.EMS_BUSINESSTYPE_MASTER
where n.BUSINESSTYPE_ID == 1
select n).ToList();
}
else
{
var x = from n in db.EMS_BUSINESSTYPE_MASTER
select n;
}
return x;
}
Here if I provide return x I'm getting an error.
As was pointed out, x was not defined at a level that the return statement could reach. So we've just moved that out into it's own definition and ensured that the else block .ToList()'s the result. hope this helps.
public List<EMS_BUSINESSTYPE_MASTER> CustomerType(int Cust)
{
List<EMS_BUSINESSTYPE_MASTER> x = new List<EMS_BUSINESS_TYPE>();
if (Cust == 1)
{
x = (from n in db.EMS_BUSINESSTYPE_MASTER
where n.BUSINESSTYPE_ID == 1
select n).ToList();
}
else
{
x = (from n in db.EMS_BUSINESSTYPE_MASTER
select n).ToList();
}
return x;
}
I would suggest an approach like below.
x is set to one of the cases, and then if the if condition is met it is reassigned with the specific results for that scenario (i.e. business type of 1).
public IEnumerable<EMS_BUSINESSTYPE_MASTER> CustomerType(int Cust)
{
var x = db.EMS_BUSINESSTYPE_MASTER; // no need for the `select`
if (Cust == 1)
{
x = x.Where(z => z.BUSINESSTYPE_ID == 1);
}
return x;
}
The reason this helps is due to how scoping works in C#. Outside of the if and else the x (in your original code) effectively didn't exist. By declaring the x variable before the if it exists even outside of the if.

Converting string expression to boolean logic - C#

I want to convert a string expression to a real boolean expression.
The expression below will be an input (string):
"(!A && B && C) || (A && !B && C) || (A && B && !C) || (A && B && C)"
The variables A, B and C will have your boolean values (true or false).
How I can transforming a string expression, replace the logic values and validate using C#?
If you don't want to use some available libraries to parse that string you need to separate those characters and implement the logic based on comparison. So for example say we have "a || b", we can loop though each character and decide the appropriate operation based on char == '|'. For more complex situation I'd use a stack to keep track of each results, like this one that can handle && and || without parentheses:
public bool ConvertToBool(string op, bool a, bool b)
{
var st = new Stack<bool>();
var opArray = op.ToCharArray();
var orFlag = false;
var andFlag = false;
for (var i = 0; i < opArray.Length; i++)
{
bool top;
switch (opArray[i])
{
case '|':
i++;
orFlag = true;
break;
case '&':
i++;
andFlag = true;
break;
case 'a':
if (orFlag)
{
top = st.Pop();
st.Push(top || a);
orFlag = false;
}
else if (andFlag)
{
top = st.Pop();
st.Push(top && a);
andFlag = false;
continue;
}
st.Push(a);
break;
case 'b':
if (orFlag)
{
top = st.Pop();
st.Push(top && b);
orFlag = false;
}
else if (andFlag)
{
top = st.Pop();
st.Push(top && b);
andFlag = false;
continue;
}
st.Push(b);
break;
}
}
return st.Pop();
}

How do I swap 2 elements in a list [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Swap two items in List<T>
Edit: Maybe this will work for getting the 'b' value?
for (int i = 0; i < inventory.Count; i++)
{
if (inventory[a].ItemRectangle.Intersects(inventory[i].ItemRectangle))
{
itemB = inventory[i];
}
}
Edit: Here's my progress.
Item itemA;
Item itemB;
int a = -1;
int b = -1;
if (a != -1 && b != -1)
{
itemA = inventory[a];
itemB = inventory[b];
Swap(ref itemA, ref itemB);
inventory[a] = itemA;
inventory[b] = itemB;
}
And here's is where I'm getting the 'a' value.
if (item.ItemSelected == true)
{
a = item.ItemIndex;
}
else
a = -1;
I haven't figured out how to get the 'b' value because I would have to check for an item colliding with another item that are both in the same list. If anybody know how I can do this, please tell me. It would look something like this I guess:
if (item.ItemRectangle.Intersects(//the other item.ItemRectangle)
{
b = item.ItemIndex;
}
else
b = -1;
I've made a List < Item > called inventory. So now I want to implement a swap function, like this:
foreach (Item item in inventory)
{
if (mouseRectangle.Intersects(item.ItemRectangle))
{
if (Input.EdgeDetectLeftMouseDown())
{
switch (item.ItemSelected)
{
case false:
item.ItemSelected = true;
break;
case true:
item.ItemSelected = false;
break;
}
}
}
else if (Input.EdgeDetectLeftMouseDown())
{
switch (item.ItemSelected)
{
case true:
item.ItemSelected = false;
break;
}
}
else if (item.ItemSelected == true)
{
item.ItemPosition = new Vector2(mouseRectangle.X, mouseRectangle.Y);
item.ItemRectangle = new Rectangle(mouseRectangle.X, mouseRectangle.Y, 32, 32);
}
else if (item.ItemSelected == false && //a lot of checks to determine it is not intersecting with an equip slot
{
item.ItemPosition = item.OriginItemPosition;
item.ItemRectangle = item.OriginItemRectangle;
}
else if (item.ItemRectangle.Intersects(item.ItemRectangle))
{
//SwapItem(inventory, item, item);
}
So that's the part of the code I need help with. I want any item in the list to be able to swap with any other item in the list. My SwapItem method is just a placeholder, I dont actually have a SwapItem method yet.
I want the arguments that you pass in to the method to be related to the items I want to swap. So the first item would be the item that I have selected with my mouse, and the other item should be the item that the first item is intersecting with.
To swap an element of the list you can write an extension method as.
public static class ExtensionMethods
{
public static void Swap<T>(this List<T> list, int index1, int index2)
{
T temp = list[index1];
list[index1] = list[index2];
list[index2] = temp;
}
}
Remember to put the extension method inside a static class.
then you can do:
yourList.Swap(0,1); // swap element at index 0 with element at index 1
To swap the values of two variables, the easiest method is using references. This is a classic pointer exercise in c++, but it can apply to C# as well.
// Replace int with any data type / class you need
void Swap (ref int a, ref int b)
{
int c = a;
a = b;
b = c;
}
The algorithm used is very simple, and the explanation is usually done like this: you have two glasses, one with water, and one with oil. To put the oil in the first glass, you will need to use a third glass, put the water inside, then put the oil in the first glass, and the water in the second one.
Here is what I had in mind. Look for the comments, so you can understand what's going on.:
// Unlike foreach, with for I can change the values in the list
for (int i = 0; i < inventory.Count; i++)
{
if (mouseRectangle.Intersects(inventory[i].ItemRectangle))
{
if (Input.EdgeDetectLeftMouseDown())
{
// You can replace the switch with this shorter structure
// if A is a bool value, !A will have the opposite value
inventory[i].ItemSelected = !inventory[i].ItemSelected;
}
}
else if (Input.EdgeDetectLeftMouseDown())
{
// You don't need a case-switch for a single condition. An if should suffice
if (inventory[i].ItemSelected)
inventory[i].ItemSelected = false;
}
else if (inventory[i].ItemSelected == true)
{
inventory[i].ItemPosition = new Vector2(mouseRectangle.X, mouseRectangle.Y);
inventory[i].ItemRectangle = new Rectangle(mouseRectangle.X, mouseRectangle.Y, 32, 32);
}
else if (inventory[i].ItemSelected == false && //a lot of checks to determine it is not intersecting with an equip slot
{
inventory[i].ItemPosition = inventory[i].OriginItemPosition;
inventory[i].ItemRectangle = inventory[i].OriginItemRectangle;
}
// Something definitely wrong with this line, a rectangle to instersect with itself??
else if (inventory[i].ItemRectangle.Intersects(inventory[PROBABLY_SOMETHING_ELSE].ItemRectangle))
{
Swap (ref inventory[i], ref inventory[PROBABLY_SOMETHING_ELSE])
}
}

Sorting List of Strings

I'm having a List<String> l_lstTemp and which contains
"A1"
"A1_1"
"A1_2"
"1A"
"B2_1"
"B1_2"
"B1_1_2"
"A10"
"B11"
"A"
"Z"
I need to sort the items based on the character and numeric value.
So the sorted list will be like
"1A"
"A"
"A1"
"A1_1"
"A1_2"
"A10"
"B1_1_2"
"B1_2"
"B2_1"
"B11"
"Z"
Here is my code:
l_lstTemp.Sort(delegate(String One, String Two)
{
Match l_mOne = Regex.Match(One, #"(\D*)(\d*)");
Match l_mTwo = Regex.Match(Two, #"(\D*)(\d*)");
int Result;
if (l_mOne.Success || l_mTwo.Success)
{
String l_strX, l_strY;
l_strX = l_mOne.Groups[1].Value;
l_strY = l_mTwo.Groups[1].Value;
Result = l_strX.CompareTo(l_strY);
if (Result != 0)
return Result;
l_strX = l_mOne.Groups[2].Value;
l_strY = l_mTwo.Groups[2].Value;
if (l_strX == String.Empty || l_strY == String.Empty)
{
Result = l_strX.CompareTo(l_strY);
if (Result != 0)
return Result;
}
else
{
long X = long.Parse(l_strX);
long Y = long.Parse(l_strY);
Result = X.CompareTo(Y);
if (Result != 0)
return Result;
}
}
return 0 ;
}
);
But its not working (sorting) properly.
How do I modify my code to sort the list properly?
Please post me a way to do this.
Thanks in advance.
I did some modifications to your code. The thing was that when both Group 1 and Group 2 are equals, you still need to check what remains.
Important: I did the modifications inside your code, so this could be a little tricky. I really suggest you refactoring your code now that you know it works:
l.Sort(delegate(String One, String Two)
{
while (One != "" && Two != "")
{
if (One == Two)
return 0;
//Add one more group to capture what remains of the expression
Match l_mOne = Regex.Match(One, #"_*(\D*)(\d*)(.*)$");
Match l_mTwo = Regex.Match(Two, #"_*(\D*)(\d*)(.*)$");
int Result;
if (l_mOne.Success || l_mTwo.Success)
{
String l_strX, l_strY;
l_strX = l_mOne.Groups[1].Value;
l_strY = l_mTwo.Groups[1].Value;
Result = l_strX.CompareTo(l_strY);
if (Result != 0)
return Result;
l_strX = l_mOne.Groups[2].Value;
l_strY = l_mTwo.Groups[2].Value;
if (l_strX == String.Empty || l_strY == String.Empty)
{
Result = l_strX.CompareTo(l_strY);
if (Result != 0)
return Result;
}
else
{
long X = long.Parse(l_strX);
long Y = long.Parse(l_strY);
Result = X.CompareTo(Y);
if (Result != 0)
return Result;
One = l_mOne.Groups[3].Value; //Store in 'One' the remaining part of the regex
Two = l_mTwo.Groups[3].Value; //The same in Two
continue; //The result will be the result of the comparison of those two new values.
}
}
}
return One.CompareTo(Two);
});
Edit:
I also added _* to remove all the _ characters from the begining of the strings. I assumed here that the strings will only contain _ after the numbers and not something like B1B or B1$.
The thing here is that you don't really explain how the comparison should be made, and I had to assume those things from your original data and the sorted data, otherwise what would happen if you want to sort A1A and A1_? What should it return?
Here's how I would implement such a comparer. Much easier to follow IMHO.
var re = new Regex(#"^(\d+)?([A-Z]+)(\d+)?(?:_(\d+)(?:_(\d+))?)?$");
Func<Group, int, int> intOrDefault = (g, d) => g.Success ? Convert.ToInt32(g.Value) : d;
list.Sort((x, y) =>
{
var xm = re.Match(x);
var ym = re.Match(y);
int cmp;
// compare the first group
// compare the leading numbers (if any)
cmp = intOrDefault(xm.Groups[1], int.MaxValue).CompareTo(intOrDefault(ym.Groups[1], int.MaxValue));
if (cmp != 0)
return cmp;
// compare letters
cmp = xm.Groups[2].Value.CompareTo(ym.Groups[2].Value);
if (cmp != 0)
return cmp;
// compare the trailing numbers (if any)
cmp = intOrDefault(xm.Groups[3], 0).CompareTo(intOrDefault(ym.Groups[3], 0));
if (cmp != 0)
return cmp;
// compare the next group
cmp = intOrDefault(xm.Groups[4], 0).CompareTo(intOrDefault(ym.Groups[4], 0));
if (cmp != 0)
return cmp;
// compare the last group
cmp = intOrDefault(xm.Groups[5], 0).CompareTo(intOrDefault(ym.Groups[5], 0));
return cmp;
});
For this example, just calling sort l_lstTemp.Sort() would get you the result you are looking for

Categories

Resources