ManInMoon
ManInMoon

Reputation: 7005

How to I use LINQ to get last date only

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

Answers (4)

Uilque Messias
Uilque Messias

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

Jake
Jake

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

Erik Philips
Erik Philips

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

Habib
Habib

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:

  • Apply filter for Date
  • Group filtered values based on Name
  • Select 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

Related Questions