Method that checks if two items collide - refactoring

I am using the following method to check if 2 items share the same index:
function doIndexesColide(itemA,itemB){
return ((itemA.startIndex >= itemB.startIndex) && (itemA.startIndex <= itemB.endIndex))
|| ((itemA.endIndex >= itemB.startIndex) && (itemA.endIndex <= itemB.endIndex))
|| ((itemA.startIndex <= itemB.startIndex) && (itemA.endIndex >= itemB.endIndex))
}
Which works fine , but i feel it could be a simpler method and would like to refactor.
This is the spec for the method - given 2 items with start-end index values , return true/false if items collide (consider only the start/end index , this is not a graphic collision detection but only consider the indexes)

Related

Add a Contains("string") functionality Azure Table LINQpad query?

OK, this doesn't work due to Azure Table query subset constraints:
var res = tcmarketnlog.Where(t => t.Level == level && t.Message.Contains("151207151510") && t.Timestamp >= start && t.Timestamp <= end).Take(1000);
The t.Message.Contains("151207151510") bombs. However, there must be some way to then search the results in LINQpad and select only the results with this string in the message.
For example, I could not coerce the result into a variable that was then queriable again with LINQ. Any tips?
If you can't use string.Contains on an Azure Table Queryable, you can still turn it into an Enumerable and then apply the additional filter to only show the results you want. However, it means that it will return all records that meet the other criteria over the network before then limiting them on the client side to only those rows where the Message field contains the specified string.
var res = tcmarketnlog.Where(t => t.Level == level && t.Timestamp >= start && t.Timestamp <= end).AsEnumerable().Where(t => t.Message.Contains("151207151510")).Take(1000);
Maybe message is null. Just check message null before contains. pls try this:
var res = tcmarketnlog.Where(t => t.Level == level
&& t.Message != null && t.Message.Contains("151207151510")
&& t.Timestamp >= start && t.Timestamp <= end).Take(1000);

LINQ Error The type is not supported in aggregation operations

I have LINQ code and I receive the following error: System.ServiceModel.FaultException: The type 'ObjectMgmt' is not supported in aggregation operations.
(from cinnost in edc.CinnostSOPs
where cinnost.LegislativneVyznamna == true &&
cinnost.ObjektId == objektid
select (from o in edc.PlanRealizaces
where o.CinnostSOPIdSOP == cinnost.IdSOP &&
o.DatumPlatnosti <= DateTime.Now &&
o.Provest == true &&
o.DatumProvedeni == null
orderby o.DatumPlatnosti descending
select new ObjectMgmt
{
Datum = (DateTime.Now.Date - o.DatumPlatnosti.Value).TotalDays
}).Max(m => m)).ToList<ObjectMgmt>();
The message speaks of an aggregate. The only aggregate I see is the Max call. This is the hint needed to debug the problem.
You care calculating the max of a sequence of ObjectMgmt instances which is obviously not possible. Change that to what you really meant.
The compiler error you get tells you that ObjectMgmt can not be used as the source of an aggregation. This happens because Max requires that the ObjectMgmt type implements IComparable.
After formatting your query to make it more readable it seems that you want to find the ObjectMgmt instance where Datum has the maximum value.
Since you already ordered the values descending by DatumPlatnosti you know that the ObjectMgmt instances are ordered by increasing Datum values. Therefore you don't need an aggregation at all. Just take the last element of the sequence (I would however order ascending and then take the first element).
(from cinnost in edc.CinnostSOPs
where cinnost.LegislativneVyznamna == true &&
cinnost.ObjektId == objektid
select (from o in edc.PlanRealizaces
where o.CinnostSOPIdSOP == cinnost.IdSOP &&
o.DatumPlatnosti <= DateTime.Now &&
o.Provest == true &&
o.DatumProvedeni == null
orderby o.DatumPlatnosti
select new ObjectMgmt
{
Datum = (DateTime.Now.Date - o.DatumPlatnosti.Value).TotalDays
}).First()).ToList<ObjectMgmt>();
Because your ObjectMgmt objects have only one property filled by query: Datum, change your Max call to get max of Datum, not the ObjectMgmt itself:
(from cinnost in edc.CinnostSOPs
where cinnost.LegislativneVyznamna == true &&
cinnost.ObjektId == objektid
select (from o in edc.PlanRealizaces
where o.CinnostSOPIdSOP == cinnost.IdSOP &&
o.DatumPlatnosti <= DateTime.Now &&
o.Provest == true &&
o.DatumProvedeni == null
orderby o.DatumPlatnosti descending
select new ObjectMgmt
{
Datum = (DateTime.Now.Date - o.DatumPlatnosti.Value).TotalDays
}).Max(m => m.Datum)).ToList<ObjectMgmt>();

Why is LINQ query to DataTable not working?

I have a DataTable, dt, that contains the following:
As you can see, there are two sets of files here: baseline (columns 1-3) and target (columns 4-6). So in this case I have 4 baseline files, m4, m5, m1, and m3 (m1 in row 5 is copied from row 3) and one target file, m1. The problem is that the information for the baseline file m1.txt is duplicated, so I'm trying to remove it using the following LINQ statement:
var extraneousRows = dt.Rows.Cast<DataRow>().
Where(
row => row["BASELINE_FOLDER"] == baselineSubfolder
&& row["BASELINE_FILE"] == baselineFilename
&& row["BASELINE_CHECKSUM"] == baselineChecksum
&& row["STATUS"] == "remove"
).ToArray();
foreach (DataRow dr in extraneousRows)
{
dt.Rows.Remove(dr);
}
This should remove the 3rd row from the DataTable but it doesn't. The code works fine if I omit the && row["STATUS"] == "remove" line, so I know it's functional. And the values for baselineSubfolder, baselineFilename, and baselineChecksum are correct, so that's not the problem.
But for some reason, when I include that line about the status column, it doesn't detect that that row is in the DataTable, even though it clearly is according to the DataSet Visualizer (photo above). So it's never entering the foreach loop and not removing the necessary files. Why???
I maybe should mention that the baseline file information (first 4 rows) are being retrieved from a database, whereas the target file fields are being generated according to user input. I don't see how it would matter where the information is coming from, though, since I'm querying the DataTable directly...
UPDATE
Ok, after following the suggestions of idipous and Jamie Keeling, I've determined that the problem had to do with the foreach loop, which was never being populated. Since this query should only ever return a single row, I eliminated the loop altogether. My revised code looks like this:
var extraneousRows = dt.Rows.Cast<DataRow>().
Where(
row => row["BASELINE_FOLDER"] == baselineSubfolder
&& row["BASELINE_FILE"] == baselineFilename
&& row["BASELINE_CHECKSUM"] == baselineChecksum
&& row["STATUS"] == "remove"
).SingleOrDefault();
dt.Rows.Remove(extraneousRows);
For whatever reason, extraneousRows remains null and that last line is generating a runtime error: IndexOutOfRangeException: The given DataRow is not in the current DataRowCollection
Why isn't this working?
It actually turns out that the problem was that I needed to cast the column values to strings. The solution was incredibly simple: just add a .ToString() after the column names and viola! The following code worked like a charm:
var extraneousRows = dt.Rows.Cast<DataRow>().
Where(
row => row["BASELINE_FOLDER"].ToString() == baselineSubfolder
&& row["BASELINE_FILE"].ToString() == baselineFilename
&& row["BASELINE_CHECKSUM"].ToString() == baselineChecksum
&& row["STATUS"].ToString() == "remove"
).SingleOrDefault();
dt.Rows.Remove(extraneousRows);
I also found a non-LINQ way to do this, by iterating through all the rows of the DataTable. It's not the most efficient, but it works:
for (int z = 0; z < dt.Rows.Count; z++)
{
if ((dt.Rows[z]["BASELINE_FOLDER"].ToString() == baselineSubfolder)
&& (dt.Rows[z]["BASELINE_FILE"].ToString() == baselineFilename)
&& (dt.Rows[z]["BASELINE_CHECKSUM"].ToString() == baselineChecksum)
&& (dt.Rows[z]["STATUS"].ToString() == "remove"))
{
dt.Rows[z].Delete();
}
}
dt.AcceptChanges();

How to use LINQ To Entities for filtering when many methods are not supported?

I have a table in SQL database:
ID Data Value
1 1 0.1
1 2 0.4
2 10 0.3
2 11 0.2
3 10 0.5
3 11 0.6
For each unique value in Data, I want to filter out the row with the largest ID. For example: In the table above, I want to filter out the third and fourth row because the fifth and sixth rows have the same Data values but their IDs (3) are larger (2 in the third and fourth row).
I tried this in Linq to Entities:
IQueryable<DerivedRate> test = ObjectContext.DerivedRates.OrderBy(d => d.Data).ThenBy(d => d.ID).SkipWhile((d, index) => (index == size - 1) || (d.ID != ObjectContext.DerivedRates.ElementAt(index + 1).ID));
Basically, I am sorting the list and removing the duplicates by checking if the next element has an identical ID.
However, this doesn't work because SkipWhile(index) and ElementAt(index) aren't supported in Linq to Entities. I don't want to pull the entire gigantic table into an array before sorting it. Is there a way?
You can use the GroupBy and Max function for that.
IQueryable<DerivedRate> test = (from d in ObjectContext.DerivedRates
let grouped = ObjectContext.DerivedRates.GroupBy(dr => dr.Data).First()
where d.Data == grouped.Key && d.ID == grouped.Max(dg => dg.ID)
orderby d.Data
select d);
Femaref's solution is interesting, unfortunately, it doesn't work because an exception is thrown whenever "ObjectContext.DerivedRates.GroupBy(dr => dr.Data).First()" is executed.
His idea has inspired me for another solution, something like this:
var query = from d in ObjectContext.ProviderRates
where d.ValueDate == valueDate && d.RevisionID <= valueDateRevision.RevisionID
group d by d.RateDefID into g
select g.OrderByDescending(dd => dd.RevisionID).FirstOrDefault();
Now this works.

LINQ - Return Value From Field With A Max Value if No Rows Found

I have a table like this...
ID Description LowThreshold HighThreshold
1 BAD 0.0 .69
2 MEETS .70 .89
3 GOOD .90 2
The object here is to write a LINQ query that will select the right Description based on a given decimal. For instance .75 is between .70 and .89, so it would return “MEETS”. BUT, the kicker is, if the Number is higher than all the ranges, automatically return the Description for the record with the highest HighThreshold. So, if I pass in 5, I should get “GOOD” returned.
I have this so far, but it errors out with scores higher than 2, obviously:
private string GetEvaluationDescription (decimal score)
{
string evaluationText = myContext.PerformanceRanges.Where
(e =>
e.LowThreshold <= score
&&
e.HighThreshold >= score
)
.Select(eval => eval.Description).First().ToString();
}
I'd like to accomplish this with just this one query, but my imagination isn't getting me there. I attempted what I found in this post but couldn't get it to work
What about this:
var range = myContext.PerformanceRanges
.SingleOrDefault(e=>e.LowThreshold <= score && e.HighThreshold >= score)??
PerformanceRanges.Single(
e=>e.HighThreshold == PerformanceRanges
.Max(p=> p.HighThreshold)
);
string evaluationText = range.Description;
The range query will select the element that matches with the Thereshold ranges, and if the value is greater (the first query will return null), it will select the greatest range.
What about this:
string evaluationText = myContext.PerformanceRanges.Where
(e =>
(e.LowThreshold <= score
&&
e.HighThreshold >= score) ||
(e.HighThreshold ==
myContext.PerformanceRanges.Max (
x => x.HighThreshold)
&& score > e.HighThreshold )
)
.Select(eval => eval.Description).First().ToString();

Resources