将一个List <customtype>复杂合并到另一个</customtype>中

时间:2012-05-23 19:03:17

标签: c# .net linq

我需要按时间顺序返回警报列表。下面的方法1做到了这一点。

我还需要获取某种警报类型的警报,以便如果AlertTypeID = {1,2,3,6,8,9,x},则通过CreateDate返回这些警报并按月进行排序。 下面的方法2就是这样做的。

现在,我需要将方法2的结果插入到方法1的结果中。 即使方法2返回的项目按月组织,我们也只是 关心最近的。只有方法2中最新的子组项需要遵循从方法1返回的项的时间顺序。此子组 item将确定子组2中其余每月项目的位置。

最后一项要求是必须删除重复项。如果正在退货 从子组警报中,它不能也存在于主组警报中。

下面我举例说明了我想要达到的效果:

december alert 1 (12/23/2012)
december alert 2 (12/21/2012)
december alert 3 (12/20/2012)
december subalert 1 (12/19/2012)
december subalert 2 (12/18/2012)
december subalert 3 (12/04/2012)
december subalert 4 (12/01/2012)
december alert 4 (12/18/2012)
december alert 5 (12/12/2012)
november alert 1 (11/22/2012)
november alert 2 (11/16/2012)
november subalert 1 (11/14/2012)
november subalert 2 (11/08/2012)
november alert 3 (11/12/2012)

代码:

  1. 所有提醒按日期时间

    List<Alert> result = new List<Alert>();
    using(NeuroLabLinqDataContext dc = conn.GetContext())
    {
        IEnumerable<Alert> alerts = (from a in dc.Alerts
                                     where a.AccountID == AccountID
                                     orderby a.CreateDate descending
                                     select a).Take(40);
        result = alerts.ToList();
    }
    return result;
    
  2. 按月提醒的警报类型

    List<Alert> result = new List<Alert>();
    int[] alertTypes = {1,2,3,4,5,6,7,8,9};
    
    using (NeuroLabLinqDataContext dc = conn.GetContext())
    {
        IEnumerable<Alert> alerts = (from a in dc.Alerts
                                     where a.AccountID == AccountID &&
                                     alertTypes.Contains(a.AlertTypeID)
                                     orderby ((DateTime)a.CreateDate).Month ascending
                                     select a).ToList();
    }
    
    return result;
    
  3. 最终select语句的分组应如下所示:

     select new { Date = alerts.CreateDate, 
                  Message = alerts.Message, 
                  Type = alert.AlertTypeID, 
                  RecentActivity = [if from method 2, then true] };
    

    更新:已更新方法

     public List<Alert> GetAlertsByAccountID(Int32 AccountID, params int[] alertTypes)
            {
    
                List<Alert> result = new List<Alert>();
    
                using (NeuroLabLinqDataContext dc = conn.GetContext())
                {
                    var all = (from a in dc.Alerts
                               where a.AccountID == AccountID
                               orderby a.CreateDate descending
                               select a);
    
                    int abc = all.Count();
    
                    var first = all
                        .Where(a => a.AccountID == AccountID) && !alertTypes.Contains(a.AlertTypeID))
                        .OrderByDescending(a => a.CreateDate)
                        .GroupBy(a => a.CreateDate.Date)
                        .ToDictionary(g => g.Key);
    
                    var firstKeys = first.Keys.Cast<DateTime>()
                        .ToList().OrderBy(k => k);
    
                    var second = all
                        .Where(a => a.AccountID == AccountID) && alertTypes.Contains(a.AlertTypeID))
                        .OrderBy(a => a.CreateDate.Month)
                        .GroupBy(a => a.CreateDate.Month)
                        .ToDictionary(g => firstKeys
                            .First(k => k > g.OrderByDescending(a => a.CreateDate)
                            .FirstOrDefault().CreateDate));
    
                    var combined = first
                        .GroupJoin(
                            second,
                            fk => fk.Key,
                            sk => sk.Key,
                            (d, l) => d.Value
                                .Union(l.SelectMany(i => i.Value).ToArray()))
                        .SelectMany(i => i);
    
                        result = combined.ToList(); 
                }
    
                return result;
    
            }
    

    感谢约翰,我更进一步。目前,我收到以下错误:

      

    序列不包含匹配元素

    在这一行(我很确定):

    .First(k => k > g.OrderByDescending(a => a.CreateDate)
    

    对于它的价值,这里是我的警报表中的数据。

    AlertID AccountID   CreateDate  Timestamp   AlertTypeID    Message
    122 5   2008-03-11 20:48:07.983 0x00000000000128FB  9        sdfs
    123 1   2008-03-11 20:48:39.957 0x00000000000128FE  8        sdfsd
    124 5   2008-03-11 20:48:39.977 0x00000000000128FF  8        sdfs
    125 5   2008-03-11 20:48:40.017 0x0000000000012901  8        asdfa
    126 1   2008-03-12 22:57:42.160 0x00000000000130B3  4        sfsf
    127 5   2008-03-12 22:57:42.337 0x00000000000130B4  4        sdfsd
    128 5   2008-03-13 09:42:14.237 0x0000000000013889  4        sdfsd
    129 5   2008-03-13 09:42:31.957 0x000000000001388B  4        sdfsd
    130 5   2008-03-13 09:42:45.397 0x000000000001388D  5        asdfsdf
    131 1   2008-03-16 14:52:17.197 0x0000000000014822  9        asdfsdf
    132 1   2008-04-12 15:25:17.330 0x000000000001B582  3        sfasdf
    133 5   2008-04-12 15:25:17.700 0x000000000001B583  3        dfsfds
    134 6   2008-04-14 08:37:03.273 0x000000000001BD87  3        aasfsd
    135 6   2008-04-14 08:37:15.270 0x000000000001BD89  3        fhfsdf
    136 6   2008-04-14 08:38:45.120 0x000000000001BD8B  2        ghsdgd
    137 6   2008-04-14 08:41:30.407 0x000000000001BD9A  4        fghsdfg
    138 6   2008-04-14 08:42:30.800 0x000000000001BD9C  4        gfsdf
    139 6   2008-04-14 08:42:43.763 0x000000000001BD9E  5        sdfsdf
    140 6   2008-04-14 08:49:25.450 0x000000000001BDAA  9        sdfasdfa
    141 6   2008-04-14 08:49:34.237 0x000000000001BDAC  9        sdfasdf
    142 1   2008-04-14 08:50:23.380 0x000000000001BDAF  8        sdfhdfhsg
    143 6   2008-04-14 08:50:23.567 0x000000000001BDB0  8        dgasdf
    144 5   2008-04-14 08:50:23.690 0x000000000001BDB1  8        dgasdf
    145 6   2008-04-14 08:50:23.747 0x000000000001BDB2  8         dgasdf
    147 1   2008-06-24 14:22:41.183 0x00000000000222E6  14       dgasdf
    148 5   2008-06-24 14:22:41.617 0x00000000000222E7  14       dgasdf
    149 6   2008-06-24 14:22:41.623 0x00000000000222E8  14       dgasdf
    150 1   2008-06-24 20:11:57.757 0x0000000000022AB3  13     dgasdf
    151 5   2008-06-24 20:11:57.947 0x0000000000022AB4  13       dgasdf
    152 6   2008-06-24 20:11:57.953 0x0000000000022AB5  13       dgasdf
    153 1   2008-07-03 18:41:51.067 0x0000000000028888  14       dgasdf
    154 5   2008-07-03 18:41:51.230 0x0000000000028889  14        dgasdf
    155 6   2008-07-03 18:41:51.237 0x000000000002888A  14        dgasdf
    156 1   2008-07-03 18:46:17.873 0x000000000002888D  14       dgasdf
    157 5   2008-07-03 18:46:17.937 0x000000000002888E  14       dgasdf
    158 6   2008-07-03 18:46:17.940 0x000000000002888F  14        dgasdf
    

1 个答案:

答案 0 :(得分:3)

关键是将两个组分成字典,使用第一个列表中的日期作为字典的键,并在第二个列表项日期之后选择最接近的键作为第二个字典的键。

如果您有两个词典,每个词典都使用类型和子类型的公共键值,您只需执行GroupJoinSelectMany即可将结果输入到排序列表中。

(*请注意,答案是基于稍微不同的早期版本的问题,我不会花时间更新答案,因为我认为已经在这个答案中说明和解决了基本问题)

更新2 我意识到你在First()调用中看到的问题是你的一些subalert项可能比任何其他警报项更新,这会导致你的异常。我通过使用DateTime::MaxValue向第一个字典添加'代理'键来解决这个问题,然后我不再从第一个列表中过滤出子图,我只是在最终结果上使用.Distinct()来删除重复项

使用linqpad我模拟了这个问题,并使用词典和GroupJoin

解决了这个问题
var all = new []{
    new {date = DateTime.Parse("2012-12-23"), type = "alert", value = 1, accountId = 333 },
    new {date = DateTime.Parse("2012-12-21"), type = "alert", value = 2, accountId = 333 },
    new {date = DateTime.Parse("2012-12-20"), type = "alert", value = 3, accountId = 333 },
    new {date = DateTime.Parse("2012-12-18"), type = "alert", value = 4, accountId = 333 },
    new {date = DateTime.Parse("2012-12-12"), type = "alert", value = 5, accountId = 333 },
    new {date = DateTime.Parse("2012-11-22"), type = "alert", value = 1, accountId = 333 },
    new {date = DateTime.Parse("2012-11-16"), type = "alert", value = 2, accountId = 333 },
    new {date = DateTime.Parse("2012-11-12"), type = "alert", value = 3, accountId = 333 },
    new {date = DateTime.Parse("2012-12-19"), type = "subalert", value = 1, accountId = 333 },
    new {date = DateTime.Parse("2012-12-18"), type = "subalert", value = 2, accountId = 333 },
    new {date = DateTime.Parse("2012-12-04"), type = "subalert", value = 3, accountId = 333 },
    new {date = DateTime.Parse("2012-12-01"), type = "subalert", value = 4, accountId = 333 },
    new {date = DateTime.Parse("2012-11-14"), type = "subalert", value = 1, accountId = 333 },
    new {date = DateTime.Parse("2012-11-08"), type = "subalert", value = 2, accountId = 333 },  
/*add*/ new {date = DateTime.Parse("2012-12-25"), type = "subalert", value = 9, accountId = 333 },  
};

var first = all
    .Where(a=>a.accountId == 333 /* removed && type != "alert" */)
    .OrderByDescending(a=>a.date)
    .GroupBy(a=>a.date.Date)
    .ToDictionary(g=>g.Key);

var firstKeys = first.Keys
    .Cast<DateTime>()
    .Union(new []{DateTime.MaxValue}) /* added this 'surrogate' key */
    .OrderBy(k=>k)
    .ToArray();

var second = all
    .Where(a=>a.accountId == 333 && a.type == "subalert")
    .OrderBy(a=>a.date.Month)
    .GroupBy(a=>a.date.Month)
    .ToDictionary(g=>firstKeys.First(k=>k > g.OrderByDescending(a=>a.date).FirstOrDefault().date));


var combined = first
    .GroupJoin(
        second,
        fk=>fk.Key,
        sk=>sk.Key,
        (d,l)=>d.Value
            .Union(l.SelectMany(i=>i.Value).ToArray()))
    .SelectMany(i=>i)
    .Distinct(); /* Added this to remove duplicates */

combined.Dump();

哪个收益率:

Updated Results