Boolean on List gives erratic results - c#

I have this line of code:
bool existsbuy = pricelist.Exists(element => (element <= TPbuyRange) && (element >= Convert.ToDouble(JsonResP.prices[0].closeoutBid)));
Which does not work as expected, it gives me always false.
And I modified to this, which works just fine, it gives me the boolean results as it should:
bool existsbuy1 = pricelist.Exists(element => (element <= TPbuyRange) );
bool existsbuy2 = pricelist.Exists(element => (element >= Convert.ToDouble(JsonResP.prices[0].closeoutBid)));
Then I have this one, which is very similar to the first line, and which works fine too:
bool existssell = pricelist.Exists(element => element >= TPsellRange & element <= Convert.ToDouble(JsonResP.prices[0].closeoutBid));
So I don't get it, what is wrong here?

Consider this:
list = 10,20,30
list.Exists(e => e < 20 && e > 20); //false, no element is less than 20 and also greater than 20
Versus
list.Exists(e => e < 20); //true, element 10 is less than 20
list.Exists(e => e > 20); //true, element 30 is greater than 20
Your other one that works might be this:
list.Exists(e => e < 30 && e > 10); //true, element 20 is less than 30 and also greater than 10
Without knowing what your values are we can't say exactly but this will be the reason
I would also point out that because your Convert.ToDouble(...) is effectively a constant you should do it outside of the LINQ lambda

If the separate conditions both return true, that suggests that the list contains at least one item that satisfies the condition element <= TPbuyRange and at least one item that satisfies the condition element >= Convert.ToDouble(JsonResP.prices[0].closeoutBid)). However, if the joint condition does not return the same value as existsbuy1 && existsbuy2, that suggests that no item in the list satisfies both conditions at the same time.

Related

Understanding parentheses within if statements [duplicate]

This question already has answers here:
C# conditional AND (&&) OR (||) precedence
(6 answers)
Closed 3 years ago.
I'm going through some C# coding exercises and have run into some operator logic that's stumped me.
The following line of code evaluates to false:
int a = 40, int b = 50;
if (a >= 20 && a <= 30 && (b < 20 || b > 30))
{
return a;
}
However, if I remove the brackets from inside the if statement, it evaluates to true.
if (a >= 20 && a <= 30 && b < 20 || b > 30)
{
return a;
}
Can anyone explain what I'm missing? Given that a isn't between 20 and 30, shouldn't it return false? I don't understand why putting the b portion of the if statement in brackets makes it evaluate to false.
Is it evaluating everything prior to "b > 30" as a single condition?
This is all to do with operator precedence.
Just like how * are evaluated first before + (we say * has a higher precedence than +), && is evaluated before ||, as specified.
In the first code snippet, you used brackets to "override" this precedence, making the || part evaluate first, just like how you can add parenthesis to the expression 1 + 2 * 3 to make it evaluate to 9 instead of 7.
a >= 20 && a <= 30 && (b < 20 || b > 30)
^^^^^^^^^^^^^^^^^
this part first
which becomes:
a >= 20 && a <= 30 && true
^^^^^^^ ^^^^^^^
now these parts
which becomes:
false && false && true
resulting in false.
In the second example however, there are no parentheses so the expression is evaluated according to the normal precedence rules:
a >= 20 && a <= 30 && b < 20 || b > 30
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
This part first
Which becomes:
false || b > 30
^^^^^^
then this
which becomes:
false || true
resulting in true.
If you look at the second part where you have removed the parenthesis, it is now divided into two subparts.
First one being : a >= 20 && a <= 30 && b < 20 This evaluates to false.
First one being : b > 30 This statement evaluates to true.
So at the end you have something like this
F || T from both the statements which should eventually give you true as end result

'accessibilityobject' threw an exception of type 'system.invalidoperationexception'

There are a lot of questions on SO about 'system.invalidoperationexception' but none of them have helped me figure this out.
I have a datatable (tab2tableExtra) that gets its values from another datatable (tab2table), which in turn gets is values from a database. tab2tableExtra only contains 4 rows and 8 columns and all its values (barring column [0]) are calculated from tab2table. Specifically two columns in tab2table are used to drive a for loop and those seem to be at the crux of the problem. These are MLevel and RLevel, which are shown in the code below.
Everything works perfectly when both the MLevel column and RLevel column have some non-null values. But if one of those columns is all nulls (DBNull.Value -which can happen on occasion), then something seems to go wrong. Interestingly, it doesn't actually cause the code to break, but it seems to mess with the calculated values in tab2tableExtra, as the entire table is null (except for column [0], which is just 1, 2, 3, 4).
Upon debugging, when either MLevel or RLevel (but not both) contains all null I see a 'system.invalidoperationexceptionfromthis`, as shown in the figure below. What causes the code to do is break out of the for loop after one iteration, and then not perform any of the rest of calculations.
This message comes from the following code:
// Add values to tab2tableExtra
// Add Levels columns
DataRow row = tab2tableExtra.NewRow();
for (int i = 1; i < 5; i++)
{
row = tab2tableExtra.NewRow();
row["Level"] = i;
tab2tableExtra.Rows.Add(row);
}
// Add participation rate column values
DataRow dr = tab2tableExtra.Rows[0];
int rowCount = tab2table.Rows.Count;
/*int countnumM = tab2table.AsEnumerable().Where(x => int.Parse(x["MLevel"].ToString()) == 1 ||
int.Parse(x["MLevel"].ToString()) == 2 || int.Parse(x["MLevel"].ToString()) == 3 ||
int.Parse(x["MLevel"].ToString()) == 4).ToList().Count;*/
int countnumM = tab2table.AsEnumerable().Select(x => int.TryParse(x["MLevel"].ToString(), out var d) ? d : (int?)null).Where(x => x >= 1 && x <= 4).Count();
int countnumRW = tab2table.AsEnumerable().Select(x => int.TryParse(x["RLevel"].ToString(), out var d) ? d : (int?)null).Where(x => x >= 1 && x <= 4).Count();
/*int countnumRW = tab2table.AsEnumerable().Where(x => int.Parse(x["RLevel"].ToString()) == 1 || int.Parse(x["RLevel"].ToString()) == 2 ||
int.Parse(x["RLevel"].ToString()) == 3 || int.Parse(x["RLevel"].ToString()) == 4).ToList().Count;*/
for (int i = 1; i < 5; i++)
{
if (countnumM > 0)
{
float levelPercM = Convert.ToInt32(tab2table.Compute("COUNT(MLevel)", "MLevel =" + i.ToString()));
tab2tableExtra.Rows[i - 1][1] = Math.Round(100 * levelPercM / countnumM, 2);
}
else
tab2tableExtra.Rows[i - 1][1] = null;
if (countnumRW > 0)
{
decimal levelPercRW = Convert.ToDecimal(tab2table.Compute("COUNT([RLevel])", "RLevel =" + i.ToString()));
tab2tableExtra.Rows[i - 1][2] = Math.Round(100 * levelPercRW / countnumRW, 2);
}
else
tab2tableExtra.Rows[i - 1][2] = null;
}
// Add the rest of the column values that only require a single number
tab2tableExtra.Rows[0][3] = rowCount;
if (countnumM > 0)
tab2tableExtra.Rows[0][4] = 100*countnumM/rowCount;
else
tab2tableExtra.Rows[0][4] = null;
if (countnumRW > 0)
tab2tableExtra.Rows[0][5] = 100*countnumRW/rowCount;
else
tab2tableExtra.Rows[0][5] = null;
decimal RWavg = Convert.ToDecimal(tab2table.Compute("AVG([ROverall])", ""));
decimal Mavg = Convert.ToDecimal(tab2table.Compute("AVG([MOverall])", ""));
tab2tableExtra.Rows[0][6] = RWavg;
tab2tableExtra.Rows[0][7] = Mavg;
For reference, when I debug with a tab2table that has at least one non-null value in both MLevel and RLevel, I see this:
If anyone knows how to solve this, or even just why this happening, it would be very useful.
In these lines of code:
int countnumM = tab2table.AsEnumerable()
.Select(x => int.TryParse(x["MLevel"].ToString(), out var d) ? d : (int?)null)
.Where(x => x >= 1 && x <= 4).Count();
int countnumRW = tab2table.AsEnumerable()
.Select(x => int.TryParse(x["RLevel"].ToString(), out var d) ? d : (int?)null)
.Where(x => x >= 1 && x <= 4).Count();
You're using int.TryParse to read the value of x["MLevel"].
If x["MLevel"].ToString() doesn't return a string that can be parsed as an int then int.TryParse will return false. That includes if x is DBNull.Value. That won't get parsed as an int.
Then, after the TryParse, you have this: ? d : (int?)null)
In other words, if TryParse returned true - it was able to parse, then you're selecting d - the parsed value.
But if it couldn't parse the value - TryParse returned false - then you're returning (int?)null - which is effectively null.
At the end you're filtering the results for values between 1 and 4, and then counting the number of those results:
.Where(x => x >= 1 && x <= 4).Count();
Just as you described, if there were some non-null values then that Count will probably return one or more. But if there are all null values then .Count will equal 0, because no values were between 1 and 4.
In that case countnumM and/or countnumRW would equal 0.
Further down you're setting some additional values if countnumM > 0 and if countnumRW > 0. But they're not greater than 0. They are 0. If they are 0, you're code will do what you expect:
for (int i = 1; i < 5; i++)
{
if (countnumM > 0) // this is == 0
{
float levelPercM = Convert.ToInt32(tab2table.Compute("COUNT(MLevel)", "MLevel =" + i.ToString()));
tab2tableExtra.Rows[i - 1][1] = Math.Round(100 * levelPercM / countnumM, 2);
}
else // This is what's happening
tab2tableExtra.Rows[i - 1][1] = null;
if (countnumRW > 0) // this is == 0
{
decimal levelPercRW = Convert.ToDecimal(tab2table.Compute("COUNT([RLevel])", "RLevel =" + i.ToString()));
tab2tableExtra.Rows[i - 1][2] = Math.Round(100 * levelPercRW / countnumRW, 2);
}
else // This is what's happening
tab2tableExtra.Rows[i - 1][2] = null;
}
To clarify around the other part - the InvalidOperationException:
When you're in the debugger and you inspect the properties of a variable, it's going to try to display the value of each property. That's what the list of properties is in your image - it's all the properties of this.
Some of them might be properties you don't use or care about, but when it tries to read the properties so it can show them to you, the property throws an exception. So now instead of a property value it shows you the exception it got when trying to read the property.
This is understandably confusing because you're debugging trying to figure out what's going on in your code, and then you see exceptions. You wonder if they might be related to the problem.
Generally they aren't because if your code throws an exception then it stops execution of your code. That's an exception you would need to figure out. But if it doesn't stop your code from running and it's a property on some framework class (like Form.AccessibilityObject) that you aren't even using, then you can usually ignore it.
As Scott Hannen said, the problem here has nothing to do with the 'system.invalidoperationexception' exception. For anyone who comes across a similar problem, the actually issue was with the null.
It turns out, in C# datatables cannot handle null values. And instead of giving an error, it simply just stops filling the datatable once it encounters one. In order to fix this, one has to make sure to use DBNull.Value. So in the code in question, for example, changing all null to DBNull.Value will fix the issue.

Compare C# string with Sql Server decimal type

I have a scenario that I have string value in c# and in SQL server the data type is decimal and requirement is that i have to filter value like we do in string which includes (startswith,endswith,contains etc) filters. I am trying like this :
customers = customers.Where(x => Convert.ToString(x.CrmCustomerNumber).Contains(value));
but it's give me error because you can't use Convert.tostring in IQuerable. I know that I can do that
customers.ToList().Where(x => Convert.ToString(x.CrmCustomerNumber).Contains(value));
but I am doing Customer.ToList() at the end after applying all filters. is there any solution of my problem?
If the numbers are of a known size, for instance if they are all six digits, then you could just query for a value range.
Example: I'm looking for all six-digit numbers that start with 123. That's the same as saying "WHERE Value BETWEEN 123000 AND 123999". So you could query .Where(x => x >= 123000 && x <= 123999).
IF the numbers aren't all a consistent size, but at least have some practical limit, you could extend this to say .Where(x => x == 123 || (x >= 1230 && x <= 1239) || (x >= 12300 && x <= 12399) || (x >=123000 && x <= 123999). etc.
With a little math, you could make this work for any number. (x >= n * 10 && x <= ((n * 10) + 9))
EndsWith can be done using modulo math.
Contains... well... you're stuck with a table scan. In that case, you might seriously consider adding a second, perhaps computed column to the table, one that stores the same value as a string, and then indexing that column. Then, use the new column to do the searches.

Sort on anonymous type in DBQuery

I'm struggling with an issue I have to be able to retrieve data from the database efficiently.
I'm using EF 4.3/c#.
Here's my EF logic that pulls back data:
IEnumerable<Offer> GetHotOffers()
{
using (var uow = new UnitOfWork(Connection.Products))
{
var r = new Repository<Offer>(uow.Context);
return r.Find(o =>
o.OfferPopularity != null &&
o.OfferPopularity.TotalVotes > 5 && o.OfferPopularity.PctUpvotes >= 55)
.Include(o => o.OfferPopularity)
.ToList() <= this needs to be removed
.OrderByDescending(o => ** an in memory method **)
.Take(20)
.ToList();
}
}
The Find() method is simple a repository wrapper - it returns DBQuery<T>.
In the database I have 2 pieces of data:
PctUpvotes - a decimal figure showing the % up upvotes (as opposed to
downvotes). Total of both = 100.
TotalVotes - the total number of votes cast.
As you can see from the query, I'm able to narrow down the selection somewhat in the Find() method, which means its done at the database.
However, I want to order the list using data that is not readily available, but can be assumed. I decided not to put it into a computed field because it was tieing changable logic into the database.
Here's the logic I need to incorporate, it's abit like a traffic light system:
Min PctUpvotes 55%, Min TotalVotes: 5 = level 1
Min PctUpvotes 60%, Min TotalVotes: 10 = level 2
Min PctUpvotes 65%, Min TotalVotes: 15 = level 3
Min PctUpvotes 70%, Min TotalVotes: 20 = level 4
So, once I've made the base selection, need to order them by level (descending) then PctUpvotes (descending).
I could do this once the query has been converted to a list, simply by calling a method in the linq logic after the ToList(), something like this:
public static int AdjVotes(int votes, decimal pctUpvotes)
{
if (votes >= 20 && pctUpvotes > 70) return 4;
if (votes >= 15 && pctUpvotes > 65) return 3;
if (votes >= 10 && pctUpvotes > 60) return 2;
return 1;
}
However, it's done in memory, not at the database.
The question I have is: can the logic above be incorporate into the DBQuery logic so that I don't have to call ToList() twice, and have the whole thing run against the database?
Operator (bool)?(trueValue):(falseValue) is compiled to native db query; it will look a little messy though:
return r.Find(o =>
o.OfferPopularity != null &&
o.OfferPopularity.TotalVotes > 5 && o.OfferPopularity.PctUpvotes >= 55)
.Include(o => o.OfferPopularity)
.OrderByDescending(o =>
(o.OfferPopularity.TotalVotes >= 20 && o.OfferPopularity.TotalVotes > 70 ? 4 :
(o.OfferPopularity.TotalVotes >= 15 && o.OfferPopularity.TotalVotes > 65 ? 3 :
(o.OfferPopularity.TotalVotes >= 10 && o.OfferPopularity.TotalVotes > 60 ? 2 : 1))))
.Take(20)
.ToList();

Function to look through list and determine trend

So I have a list of items. Each item on the list has a property called notional. Now, the list is already sorted. What I need to do is, develop a function that sets the type of list to one of the following:
Bullet - notional is the same for every item
Amortizing - notional decreases over the course of the schedule (might stay the same from element to element but it should never go up, and should end lower)
Accreting - notional increases over the course of the schedule (might stay the same from element to element but it should never go down, and should end higher)
Rollercoaster - notional goes up and down (could end the same, higher, or lower, but shouldn't be the same for each element and shouldn't be classfied as the other types)
What would this method look like and what would be the most efficient way to go through the list and figure this out?
Thanks!
This would be a straightforward way to do it:
bool hasGoneUp = false;
bool hasGoneDown = false;
T previous = null; // T is the type of objects in the list; assuming ref type
foreach(var item in list)
{
if (previous == null) {
previous = item;
continue;
}
hasGoneUp = hasGoneUp || item.notional > previous.notional;
hasGoneDown = hasGoneDown || item.notional < previous.notional;
if(hasGoneUp && hasGoneDown) {
return Trend.Rollercoaster;
}
previous = item;
}
if (!hasGoneUp && !hasGoneDown) {
return Trend.Bullet;
}
// Exactly one of hasGoneUp and hasGoneDown is true by this point
return hasGoneUp ? Trend.Accreting : Trend.Amortizing;
Let trendOut = Bullet
Loop from First Item to Last item
2.1. If previous notional < next notional
2.1.a. If trendOut = Amortizing return RollerCoaster
2.1.b. Else set trendOut = Accreting
2.2. if Previous Notional > next notional
2.2.a. If trendOut = Accreting return RollerCoaster
2.2.b. Else set trendOut = Amortizing
return trendOut.
You could probably do something as simple as this
var changeList = new List<Integer>
for(i = 0; i < yourList.Count() - 1; i++)
{
changeList.Add(yourList.Item(i + 1) - yourList.Item(i));
}
//Determine if the nature of the list
var positiveChangeCount = changeList.Where(x => x < 0);
var negativeChangeCount = changeList.Where(x => X > 0);
if (positiveChangeCount = yourList.Count)
{
Accreting;
}
elseif (negativeChangeCount = yourList.Count)
{
Amortizing;
}
elseif (negativeChangeCount + PositiveChangeCount = 0)
{
Bullet;
}
else
{
Rollercoaster;
}
I usually start of by optimizing for simplicity first and then performance. Hence, I would start by making a second list of N-1 elements, whose {elements} are differences between the {notionals} of the first list.
Hence, for the second list, I would expect the following for the list of your needs
Bullet - ALL elements are 0
Amortising - ALL elements stay 0 or negative
Accreting - ALL elements stay 0 or positive
Rollercoaster - Elements oscillate between negative & positive
You can probably optimize it an do it in one pass. Basically, this is a discrete differentiation over your data.
bool OnlyGreaterOrEqual=true;
bool OnlyLessOrEqual=true;
foreach(int i=1;i<itemList.Count;i++){
if(itemList[i].notional>itemList[i-1].notional){
OnlyLessOrEqual=false;
}else if(itemList[i].notional<itemList[i-1].notional){
OnlyGreaterOrEqual=false;
}
}
if(OnlyGreaterOrEqual && OnlyLessOrEqual){
return "Bullet";
}else if(OnlyGreaterOrEqual){
return "Accreting":
}else if(OnlyLessOrEqual){
return "Amortizing";
}else{
return "RollerCoast";
}
This is basically a Linq implementation of Danish's answer. It'll require (worst case) 3 passes through the list, but because they are so small it won't really matter from a performance point of view. (I wrote it to work on a list of ints so you'll have to modify it easily to work with your types).
var tmp = values
.Skip(1)
.Zip( values, (first, second) => first - second )
.ToList();
var up = tmp.Any( t => t > 0 );
var down = tmp.Any( t => t < 0 );
if( up && down )
// Rollercoaster
else if( up )
// Accreting
else if( down )
// Amortizing
else
// Bullet
You could also (ab)use the Aggregate operator and Tuple to do it as one query. However, this will fail if the collection is empty and is a bit weird to use in production code.
var result = values.Skip(1).Aggregate(
Tuple.Create<int, bool, bool>( values.First(), false, false ),
( last, current ) => {
return Tuple.Create(
current,
last.Item2 || (current - last.Item1) > 0,
last.Item3 || (current - last.Item1) < 0 );
});
result will be a tuple that contains:
the last element of the collection (which is of no use)
Item2 will contain a boolean indicating whether any element was bigger than the previous element
Item3 will contain a boolean indicating whether any element was smaller than the previous element
The same switch statement as above can be used to decide which pattern your data follows.

Categories