Reputation: 7005
I have the following code:
public class ModelData
{
public string name;
public DateTime DT;
public int real;
public int trade;
public int position;
public int dayPnl;
public double ATR;
public double C2C;
public double C;
}
List<ModelData> modelData;
var priorDateRealTrades = modelData
.Where(x => x.DT.Date <= aDate.Date)
.OrderBy(x => x.DT.Date)
.ToArray();
I only really want where to select 1 element for each "name".
My query gives me all elements with a prior date and then orders them.
How can I just return one element (the most recent prior date) for each "name"?
Upvotes: 1
Views: 1543
Reputation: 531
You just have to use IEnumerable.Distinct()
and create a class that implements
IEqualityComparer<T>
.
It could be something like this:
public class ModelData
{
public string name;
public DateTime DT;
public int real;
public int trade;
public int position;
public int dayPnl;
public double ATR;
public double C2C;
public double C;
}
private class ModelDataNameComparator : IEqualityComparer<ModelData>
{
public bool Equals(ModelData x, ModelData y)
{
return x.name.Equals(x.name.ID);
}
public int GetHashCode(ModelData obj)
{
return obj.name.GetHashCode();
}
}
public class Program
{
static void Main()
{
List<ModelData> modelData = ModelRepository.GetAllModelDataFromMagicPlace();
var priorDateRealTrades = modelData.OrderByDescending(d => d.DT)
.Distinct(new ModelDataNameComparator())
.ToList();
foreach(ModelData md in priorDateREalTrades)
{
Console.WriteLine("name: {0}, Date: {1}", md.name, md.DT);
}
}
}
I hope it helps you and if do, plese mark it as answer :)
Upvotes: 0
Reputation: 574
Would something like this work for you?
var priorDateRealTrades = modelData.Where(t => t.DT <= aDate.Date && t.DT <= DateTime.Now).OrderByDescending(t => t.DT).FirstOrDefault();
Edit:
Sorry, I didn't realize that your names may be duplicated.
var priorDateRealTrades = modelData
.GroupBy(t => t.name)
.Select(t => t.Where(t2 => t2.DT <= aDate.Date && t2.DT <= DateTime.Now).OrderByDescending(t3 => t3.DT)
.FirstOrDefault());
Upvotes: 0
Reputation: 54638
Use GroupBy() and FirstOrDefault()
var priorDateRealTrades = modelData
.GroupBy(d => d.Name)
.Select(gd => gd.Where(x => x.DT.Date <= aDate.Date)
.OrderBy(x => x.DT.Date)
.First())
.ToList()
This will group by the name, and then select the first one orderd/where'd per group. This will throw an exception if no records match the date where/criteria. This may be a requirement...
OR
var priorDateRealTrades = modelData
.GroupBy(d => d.Name)
.Select(gd => gd.Where(x => x.DT.Date <= aDate.Date)
.OrderBy(x => x.DT.Date)
.FirstOrDefault())
.Where(d => d != null)
.ToList()
This will do the same as the previous, but will also filter out results that have no dates matching (they will be null) and throw no exception.
Upvotes: 3
Reputation: 223322
You can do it like:
var query = modelData
.Where(x => x.DT.Date <= aDate.Date)
.GroupBy(r => r.name)
.Select(grp => new
{
Name = grp.Key,
LastDate = grp.OrderBy(t => t.DT.Date).FirstOrDefault()
});
What it does is:
Date
Name
and only single Date
after ordering. If you are only interested in getting Date
values, then your query should be:
var query = modelData
.Where(x => x.DT.Date <= aDate.Date)
.GroupBy(r => r.name)
.Select(grp => grp.OrderBy(t => t.DT.Date).FirstOrDefault());
Upvotes: 1