如何从通用日期列表中选择不同的(按唯一月份/年份)?

时间:2012-01-04 16:14:22

标签: c# linq

因此,独特的是基于独特的月/年,而不仅仅是一个不同的月份(所以我希望2011年1月和2012年1月是截然不同的)

 // Test set of data
        List<DateTime> CompleteListOfDates = new List<DateTime>();
        CompleteListOfDates.Add(new DateTime(2011, 1, 1));
        CompleteListOfDates.Add(new DateTime(2011, 1, 5));
        CompleteListOfDates.Add(new DateTime(2011, 3, 1));
        CompleteListOfDates.Add(new DateTime(2011, 5, 1));
        CompleteListOfDates.Add(new DateTime(2011, 5, 1));
        CompleteListOfDates.Add(new DateTime(2012, 1, 1));
        CompleteListOfDates.Add(new DateTime(2012, 2, 1));

        List<DateTime> UniqueMonthYears = new List<DateTime>();

        /* need distinct list of DateTimes that are distinct by Month and Year and should be in UniqueMonthYears
         For example:
        new DateTime(2011, 1, 1)
        new DateTime(2011, 3, 1)
        new DateTime(2011, 5, 1)
        new DateTime(2012, 1, 1)
        new DateTime(2012, 2, 1)
        */

6 个答案:

答案 0 :(得分:7)

List<DateTime> result = source
  .Select(d => new DateTime(d.Year, d.Month, 1))
  .Distinct()
  .ToList();

也很有用:

ILookup<DateTime, Order> ordersByMonth = ordersSource
  .ToLookup(order => new DateTime(order.OrderDate.Year, order.OrderDate.Month, 1));

答案 1 :(得分:4)

您可以创建自己的IEqualityComparer实现,让Linq完成其余的工作,如下所示:

// implement this
public class DateTimeComparer : IEqualityComparer<DateTime>
{
    public bool Equals(DateTime x, DateTime y)
    {
        return x.Year == y.Year && x.Month == y.Month;
    }

    public int GetHashCode(DateTime obj)
    {
        return obj.Year * 100 + obj.Month;
    }
}

// use it like this
UniqueMonthYears = CompleteListOfDates.Distinct(new DateTimeComparer()).ToList();

答案 2 :(得分:2)

var uniqueMonthYears = CompleteListOfDates
                          .GroupBy(d => new{ d.Month, d.Year})
                          .Select(my => new DateTime(my.Key.Year, my.Key.Month, 1));

会给你一个IEnumerable<DateTime>

编辑:大卫B的回答更好,但是可以选择这个。

答案 3 :(得分:1)

这是我所知道的最短代码:

    List<DateTime> UniqueMonthYears = 
        CompleteListOfDates.Select(t => new DateTime(t.Year, t.Month, 1))
            .Distinct()
            .ToList();

这是更具结构性但方式性能较差的方法(仅用于演示目的)。它给出的是能够设置string GetHash(Date)Date CreateFromHash(string)函数,从而使其更通用。

代码:

private void Form1_Load(object sender, EventArgs e)
        {

            List<DateTime> CompleteListOfDates = new List<DateTime>();

            CompleteListOfDates.Add(new DateTime(2011, 1, 1));
            CompleteListOfDates.Add(new DateTime(2011, 1, 5));
            CompleteListOfDates.Add(new DateTime(2011, 3, 1));
            CompleteListOfDates.Add(new DateTime(2011, 5, 1));
            CompleteListOfDates.Add(new DateTime(2011, 5, 1));
            CompleteListOfDates.Add(new DateTime(2012, 1, 1));
            CompleteListOfDates.Add(new DateTime(2012, 2, 1));

            List<DateTime> UniqueMonthYears = 
                CompleteListOfDates.Select(t => 
                    GetDateHash(t)).Distinct().Select(t => 
                        CreateFromDateHash(t)).ToList();


            MessageBox.Show(UniqueMonthYears.Count.ToString());
        }

        private static string GetDateHash(DateTime date)
        {
            return date.ToString("MMM-yyyy");
        }

        private static DateTime CreateFromDateHash(string hash)
        {
            return DateTime.Parse("1-" + hash);
        }

答案 4 :(得分:1)

这样的东西
completeListOfDates.Select(d => new {Year = d.Year, Month = d.Month}).Distinct()

保留第一个出现日的部分基本上没有意义,但你可以这样做。

completeListOfDates.Distinct(new YearMonthComparer());

private class YearMonthComparer : IEqualityComparer<DateTime>
{
    public bool Equals(DateTime x, DateTime y)
    {
        if(x.Year != y.Year) return false;
        if(x.Month != y.Month) return false;
        return true;
    }

    public int GetHashCode(DateTime obj)
    {
        int hash = 13;
        hash = (hash * 7) + obj.Year.GetHashCode();
        hash = (hash * 7) + obj.Month.GetHashCode();
        reutrn hash;
    }
}

答案 5 :(得分:0)

噢!每个人都打败了我。 LINQ问题非常有趣。 ; - )

我不知道你想如何从列表中选择唯一的日期,所以我没有假设你想放弃它,而是在子查询中使用了First方法。显然你可以使用某种类型和谓词来改变它。

那怎么样?

var UniqueMonthYears = (from date in CompleteListOfDates
                        let month = date.Month
                        let year = date.Year
                        let day = (CompleteListOfDates.First(d => d.Month == month && d.Year == year))
                        select day).Distinct();

哦,还有奖励积分...如果你还没有,请从http://www.linqpad.net/下载Linqpad你可以很容易地尝试这种东西。