I have a Service class. One of the fields is a collection of ServicePrice objects, which have a Price and СhangeDate field.
class Service
{
ObservableCollection<ServicePrice> ServicePrices {get; set;}
// other fields
}
class ServicePrice
{
int Price {get;set;}
DateTime ChangeDate {get;set;}
}
I need method to find the price of a service that was relevant at some point in time.
public int? GetPriceAtDate(DateTime date)
{
// Do something here
int? ActualPrice = 0
return ActualPrice;
}
I was finding a solution using the LINQ MinBy function:
public int? GetPriceAtDate(DateTime date)
{
return ServicePrices.MinBy(sp => (sp.ChangeDate - date).Duration()).Price;
}
But this function will return the nearest date, but not necessarily from the past. It would be quite strange to get a price for a product from the future.
I would handle this in two phases:
Filter out everything in the future (with respect to date)
Find the latest remaining change date
public int? GetPriceAtDate(DateTime date) =>
ServicePrices
.Where(sp => sp.ChangeDate <= date)
.MaxBy(sp => sp.ChangeDate)?.Price;
Related
I have this table
CREATE TABLE Receipt
(
id INT IDENTITY(1,1) NOT NULL PRIMARY KEY,
idcustom INT NOT NULL,
idstaff INT NOT NULL,
Daypayat DATE NOT NULL,
Timepayat TIME NOT NULL,
total INT NOT NULL
)
And I want to concatenate Daypayat with Timepayat like DateTime (dd/MM/yyyy hh:mm)
Firstly do the concatenation and save the result in the specific column in SQL using the following method.
select cast(#date+' '+#time as datetime)
or you can do this to convert,
select cast(#date as datetime)+#time
and then use Datetime struct in C# to get result.
Formatting is a view / consumer concern, it should not be a domain one. The entity should expose DayPayAt and TimePayAt as their respective types. (DateTime and DateTime / Timespan) When you query the data, project it to a ViewModel/DTO which can combine those values into a PayAt DateTime, then let your view format that how you desire.
So if your entity has:
public DateTime DayPayAt { get; set; }
public Timespan TimePayAt { get; set; }
your query would be:
var receipt = context.Receipts
.Where(/*conditions...*/)
.Select(x => new
{
// other fields or related data as needed.
x.Daypayat,
x.Timepayat
}).ToList() // Materialize our query...
.Select(x => new ReceiptViewModel
{
// Copy related data from results...
PayAt = x.DayPayAt.Add(x.Timepayat);
}).ToList();
Then in your view you can format "PayAt" using whatever custom or standard formatting string you want. #Model.PayAt.ToString("g") for instance would give you the standard short date/time format for your region, or use a custom format string for something specific.
The above example does a double-projection, one to get the raw fields of interest from our entity, the second to project to the view model. This may not be necessary depending if EF can perform a DateTime.Add. (I don't believe so)
If Timepayat in the entity maps to a DateTime field, (I.e. 0000-00-00T14:20:00) then the PayAt conversion would be:
PayAt = x.DayPayAt.Add(x.Timepayat.TimeOfDay);
An alternative if you want to return the entity and handle it there is to use an unmapped property on the Receipt entity for PayAt that composes the DateTime. The caveat of that approach is that you need to remember not to reference any unmapped property in a Linq expression since it cannot be translated to SQL.
public class Receipt
{
// Mapped properties...
public DateTime Daypayat { get; set; }
public TImespan Timepayat { get; set; }
[NotMapped]
public DateTime PayAt
{
get { return Daypayat.Add(Timepayat); }
}
}
I have a list of objects with multiple properties in it. Here is the object.
public class DataPoint
{
private readonly string uniqueId;
public DataPoint(string uid)
{
this.uniqueId = uid;
}
public string UniqueId
{
get
{
return this.uniqueId;
}
}
public string ScannerID { get; set; }
public DateTime ScanDate { get; set; }
}
Now in my code, I have a giant list of these, hundreds maybe a few thousand.
Each data point object belongs to some type of scanner, and has a scan date. I want to remove any data points that were scanned on the same day except for the last one for a given machine.
I tried using LINQ as follows but this did not work. I still have many duplicate data points.
this.allData = this.allData.GroupBy(g => g.ScannerID)
.Select(s => s.OrderByDescending(o => o.ScanDate))
.First()
.ToList();`
I need to group the data points by scanner ID, because there could be data points scanned on the same day but on a different machine. I only need the last data point for a day if there are multiple.
Edit for clarification - By last data point I mean the last scanned data point for a given scan date for a given machine. I hope that helps. So when grouping by scanner ID, I then tried to order by scan date and then only keep the last scan date for days with multiple scans.
Here is some test data for 2 machines:
Unique ID Scanner ID Scan Date
A1JN221169H07 49374 2003-02-21 15:12:53.000
A1JN22116BK08 49374 2003-02-21 15:14:08.000
A1JN22116DN09 49374 2003-02-21 15:15:23.000
A1JN22116FP0A 49374 2003-02-21 15:16:37.000
A1JOA050U900J 80354 2004-10-05 10:53:24.000
A1JOA050UB30K 80354 2004-10-05 10:54:39.000
A1JOA050UD60L 80354 2004-10-05 10:55:54.000
A1JOA050UF80M 80354 2004-10-05 10:57:08.000
A1JOA0600O202 80354 2004-10-06 08:38:26.000
I want to remove any data points that were scanned on the same day except for the last one for a given machine.
So I assume you want to group by both ScanDate and ScannerID. Here is the code:
var result = dataPoints.GroupBy(i => new { i.ScanDate.Date, i.ScannerID })
.OrderByDescending(i => i.Key.Date)
.Select(i => i.First())
.ToList();
If I understand you correctly this is what you want.
var result = dataPoints.GroupBy(i => new { i.ScanDate.Date, i.ScannerID })
.Select(i => i.OrderBy(x => x.ScanDate).Last())
.ToList();
This groups by the scanner id and the day (SacnnerDate.Date will zero out the time portion), then for each grouping it orders by the ScanDate (since the groups are the same day this will order on the time) and takes the last. So for each day you will get one result for each scanner which has the latest ScanDate for that particular day.
Just as an aside, the class could be defined as
public class DataPoint
{
public DataPoint(string uid)
{
UniqueId = uid;
}
public string UniqueId {get; private set; }
public string ScannerID { get; set; }
public DateTime ScanDate { get; set; }
}
I have a list of entities opened by various users.
I keep track of each access of any entity by storing access dates and times as the following:
public class Entity
{
public int Id { get; set; }
public virtual ICollection<AccessInfo> Accesses { get; set; }
= new HashSet<AccessInfo>();
}
public class AccessInfo
{
public int Id { get; set; }
public AccessInfoType Type { get; set; }
public User User { get; set; }
public DateTime DateTime { get; set; }
}
public enum AccessInfoType
{
Create,
Read,
Update,
Delete,
}
Now I'm trying to make an algorithm that filters the most wanted contacts based on both factors: recency and frequency.
I want contacts that were accessed 5 times yesterday to be prioritized over a contact that was accessed 30 times a week ago. But in the other hand, a user that was only accessed one time today is less important.
Is there an official name for this? I'm sure people have worked on a frequency calculation like this one before, and I'd like to read about this before I spend some time coding.
I thought about calculating the sum of the access dates in recent month and sort accordingly but I'm still not sure it's the right way, I'd love to learn from the experts.
return Entities
.OrderBy(c =>
c.Accesses
.Where(a => a.Employee.UserName == UserName)
.Where(a => a.DateTime > lastMonth)
.Select(a => a.DateTime.Ticks)
.Sum());
Exponential decay is what you're looking for. See this link:
http://www.evanmiller.org/rank-hotness-with-newtons-law-of-cooling.html
I would use a heuristic that assigns points to Entities for access and uses some kind of decay on those points.
For example, you could give an entity 1 point every time it is accessed, and once every day multiply all the points by a factor of 0.8
I have 2 different classes that represent 2 types of data. The first is the unposted raw format. The second is the posted format.
public class SalesRecords
{
public long? RecordId { get; set; }
public DateTime RecordDate { get; set; }
public string RecordDesc { get; set; }
// Other non-related properties and methods
}
public class PostedSalesRecords
{
public long? CorrelationId { get; set; }
public DateTime RecordDate { get; set; }
public DateTime? PostedDate { get; set; }
public string RecordDesc { get; set; }
// Other non-related properties and methods
}
Our system has a list of sales records. These sales records are posted to a different system at a time determined by the users. I am creating a screen that will show all of the posted sales records along with the unposted sales records as a reconciliation. The datasource for my grid will be a list of PostedSalesRecords. What I need to do is find out which records out of the List<SalesRecords> that are not in List<PostedSalesRecords> and then map those unposted SalesRecords to a PostedSalesRecords. I am having trouble finding a way to quickly compare. Basically I tried this, and it was EXTREMELY slow:
private List<SalesRecords> GetUnpostedSalesRecords(
List<SalesRecords> allSalesRecords,
List<PostedSalesRecords> postedSalesRecords)
{
return allSalesRecords.Where(x => !(postedSalesRecords.Select(y => y.CorrelationId.Value).Contains(x.RecordId.Value))).ToList();
}
My biggest issue is that I am filtering through a lot of data. I am comparing ~55,000 total sales records to about 17,000 posted records. It takes about 2 minutes for me to process this. Any possible way to speed this up? Thanks!
You can try an outer join, please see if this helps with the performance:
var test = (from s in allSalesRecords
join p in postedSalesRecords on s.RecordId equals p.CorrelationId into joined
from j in joined.DefaultIfEmpty()
where j == null
select s).ToList();
Or in your implementation, you can create a dictionary of only Ids for postedSalesRecords and then use that collection in your query, it'll definitely help with performance because the lookup time will be O(1) instead of traversing through the whole collection for each record.
var postedIds = postedSalesRecords.Select(y => y.CorrelationId.Value)
.Distinct().ToDictionary(d=>d);
return allSalesRecords.Where(x => !(postedIds.ContainsKey(x.RecordId.Value))).ToList();
Using a left outer join as described on MSDN should work much more efficiently:
private List<SalesRecords> GetUnpostedSalesRecords(
List<SalesRecords> allSalesRecords,
List<PostedSalesRecords> postedSalesRecords)
{
return (from x in allSalesRecords
join y in postedSalesRecords on x.RecordId.Value
equals y.CorrelationId.Value into joined
from z in joined.DefaultIfEmpty()
where z == null
select x).ToList();
}
This will probably be implemented with a hash set. You could implement this yourself (arguably clearer that way): build a HashSet<long> of the ID values in one or both lists to ensure that you don't need repetitive O(N) lookups each time you go through the outer list.
I have a list which I want to sort and show the entries for a specific date and time.
public class Foodlist
{
public int C_ID { get; set; }
public string DateofFood{ get; set;}
public string FoodTime{ get; set;}
public string FoodDetail{ get; set;}
}
currently I am using the following code to show the list in descending order by date. The date format is same as that of the date picker.
var datetime = foodItems.OrderBy(x => x.DateofFood).ToList();
listBox1.ItemsSource = datetime;
I want to show only the entries for a specific date, say Today. Any ideas?
You can use .Where to filter the data:
listBox1.ItemsSource = orderedList;
var datetime =
foodItems
.Where(x => DateTime.Parse(x.DateofFood).Date == datePickerValue.Date) //Or whatever the date time is you're after.
.OrderBy(x => x.DateofFood)
.ToList();
It might be better to make the DateofFood a DateTime in your class though to avoid using DateTime.Parse() (or ParseExcact() if needed).
.Where(x => x.DateofFood.Date == datePickerValue.Date) //Or whatever the date time is you're after.
Notice the use of .Date to remove the Time component of the DateTime so you can find entries on a given date.
You can use Date property of DateTime structure:
var result = foodItems.OrderBy(x => x.DateofFood)
.Where(x=>x.DateofFood.Date == givenDate.Date).ToList();
U need to apply predicate in where like
var datetime = foodItems.Where(x=>x.DateofFood==DateTime.Today).ToList();
If you are storing it as string, then it might be a better option to store it as yyyyMMdd. As this will provide you simple sorting.
While you can always do System.DateTime.UtcNow.ToString("yyyyMmMdd")for comparison with above list.
var datetime = foodItems.Where(x => x.DateofFood == DateTime.Now).ToList();