C# 复杂Linq查询

C# 复杂Linq查询,c#,.net,linq,C#,.net,Linq,我在数据库中有一个表,有两个字段:索引(int)、电子邮件(varchar(100)) 我需要做以下工作: 按域名对所有电子邮件进行分组(所有电子邮件都已小写) 选择所有组中的所有电子邮件,其中域的电子邮件总数不超过步骤1之前电子邮件总数的20% 代码示例: DataContext db = new DataContext(); //Domains to group by List<string> domains = new List<string&g

我在数据库中有一个表,有两个字段:索引(int)、电子邮件(varchar(100))

我需要做以下工作:

  • 按域名对所有电子邮件进行分组(所有电子邮件都已小写)
  • 选择所有组中的所有电子邮件,其中域的电子邮件总数不超过步骤1之前电子邮件总数的20%
  • 代码示例:

        DataContext db = new DataContext();
    
        //Domains to group by
        List<string> domains = new List<string>() { "gmail.com", "yahoo.com", "hotmail.com" };
    
        Dictionary<string, List<string>> emailGroups = new Dictionary<string, List<string>>();
    
        //Init dictionary
        foreach (string thisDomain in domains)
        {
            emailGroups.Add(thisDomain, new List<string>());
        }
    
        //Get distinct emails
        var emails = db.Clients.Select(x => x.Email).Distinct();
    
        //Total emails
        int totalEmails = emails.Count();
    
        //One percent of total emails
        int onePercent = totalEmails / 100;
    
        //Run on each email
        foreach (var thisEmail in emails)
        {
            //Run on each domain
            foreach (string thisDomain in emailGroups.Keys)
            {
                //If email from this domain
                if (thisEmail.Contains(thisDomain))
                {
                    //Add to dictionary
                    emailGroups[thisDomain].Add(thisEmail);
                }
            }
        }
    
        //Will store the final result
        List<string> finalEmails = new List<string>();
    
        //Run on each domain
        foreach (string thisDomain in emailGroups.Keys)
        {
            //Get percent of emails in group
            int thisDomainPercents = emailGroups[thisDomain].Count / onePercent;
    
            //More than 20%
            if (thisDomainPercents > 20)
            {
                //Take only 20% and join to the final result
                finalEmails = finalEmails.Union(emailGroups[thisDomain].Take(20 * onePercent)).ToList();
            }
            else
            {
                //Join all to the final result
                finalEmails = finalEmails.Union(emailGroups[thisDomain]).ToList();
            }
        }
    
    DataContext db=newdatacontext();
    //要按分组的域
    List domains=new List(){“gmail.com”、“yahoo.com”、“hotmail.com”};
    Dictionary emailGroups=新字典();
    //初始字典
    foreach(在域中字符串thisDomain)
    {
    添加(thisDomain,new List());
    }
    //收到不同的电子邮件
    var emails=db.Clients.Select(x=>x.Email.Distinct();
    //电子邮件总数
    int totalEmails=emails.Count();
    //占电子邮件总数的百分之一
    int onePercent=电子邮件总数/100;
    //在每封电子邮件上运行
    foreach(电子邮件中的电子邮件)
    {
    //在每个域上运行
    foreach(在emailGroups.Keys中字符串thisDomain)
    {
    //如果来自此域的电子邮件
    如果(thisEmail.Contains(thisDomain))
    {
    //添加到字典
    emailGroups[thisDomain]。添加(thisEmail);
    }
    }
    }
    //将存储最终结果
    List finalEmails=新列表();
    //在每个域上运行
    foreach(在emailGroups.Keys中字符串thisDomain)
    {
    //获取组中电子邮件的百分比
    int thisDomainPercents=emailGroups[thisDomain]。计数/OnePercents;
    //超过20%
    如果(此域百分比>20)
    {
    //只需20%就可以加入到最终结果中
    finalEmails=finalEmails.Union(emailGroups[thisDomain].Take(20*onePercent)).ToList();
    }
    其他的
    {
    //把所有的加入到最终的结果中
    finalEmails=finalEmails.Union(emailGroups[thisDomain]).ToList();
    }
    }
    

    有人知道更好的方法吗?

    我想不出一种方法可以做到这一点而不至少两次点击数据库,一次用于分组,一次用于总计数,您可以尝试以下方法

    var query = from u in db.Users
                group u by u.Email.Split('@')[1] into g
                select new 
                {
                    Domain = g.Key,
                    Users = g.ToList()
                };
    
    query = query.Where(x => x.Users.Count <= (db.Users.Count() * 0.2));
    
    var query=from u in db.Users
    通过电子邮件将u分组。将('@')[1]拆分为g
    选择新的
    {
    域=g.密钥,
    Users=g.ToList()
    };
    
    query=query.Where(x=>x.Users.Count我想不出一种方法可以在不至少两次命中数据库的情况下执行此操作,一次用于分组,一次用于总计数,您可以尝试以下操作

    var query = from u in db.Users
                group u by u.Email.Split('@')[1] into g
                select new 
                {
                    Domain = g.Key,
                    Users = g.ToList()
                };
    
    query = query.Where(x => x.Users.Count <= (db.Users.Count() * 0.2));
    
    var query=from u in db.Users
    通过电子邮件将u分组。将('@')[1]拆分为g
    选择新的
    {
    域=g.密钥,
    Users=g.ToList()
    };
    
    query=query.Where(x=>x.Users.Count假设您希望以升序获取每个组中的最后一项:

    int m = (int) (input.Count() * 0.2);
    var result = input.GroupBy(x=>x.email.Split('@')[1],
                              (key,g)=>g.OrderByDescending(x=>x.index).Take(m)
                                        .OrderBy(x=>x.index))
                      .SelectMany(g=>g);//If you want to get the last result without grouping
    
    或者这个:

    var result = input.GroupBy(x=>x.email.Split('@')[1],
                              (key,g)=>g.OrderBy(x=>x.index)
                                        .Skip(g.Count()-m))
                      .SelectMany(g=>g);//If you want to get the last result without grouping
    

    假设您希望按升序获取每个组中的最后一项:

    int m = (int) (input.Count() * 0.2);
    var result = input.GroupBy(x=>x.email.Split('@')[1],
                              (key,g)=>g.OrderByDescending(x=>x.index).Take(m)
                                        .OrderBy(x=>x.index))
                      .SelectMany(g=>g);//If you want to get the last result without grouping
    
    或者这个:

    var result = input.GroupBy(x=>x.email.Split('@')[1],
                              (key,g)=>g.OrderBy(x=>x.index)
                                        .Skip(g.Count()-m))
                      .SelectMany(g=>g);//If you want to get the last result without grouping
    

    看起来您只是想以某种方式过滤所有结果,而分组只是实现这一目的的一个跳板?顺便问一下,您能否更清楚地说明为什么
    101102
    而不是
    100101
    ,对于
    104105
    也一样,但不是
    103104
    ?从下到上收集项目?您能否确认是否要完成如果某个域的总计数超过了总计数,或者如果您希望包含所有达到阈值的电子邮件,请将其排除在外?我只需要接收所有电子邮件,直到treshold@KonstantinFedoseev你检查过我的解决方案吗?如果它不起作用,请留下一些评论让我知道,我想知道它是如何起作用的。看起来你只是想过滤呃,所有的结果在某种程度上和分组只是实现这一点的跳板?顺便说一句,你能更清楚地说明为什么
    101102
    而不是
    100101
    ,对于
    104105
    而不是
    103104
    ,从下到上收集项目吗?你能确认一下,如果一个域是tot,你是否想完全排除它吗al count超过总数,或者如果你想包含所有达到阈值的电子邮件?我只需要接收所有电子邮件,直到treshold@KonstantinFedoseev你检查过我的解决方案吗?如果它不起作用,请留下一些评论让我知道,我想知道它是如何起作用的。也许可以添加let userCount=db.Users.Count()*0.2您可以在不点击两次db的情况下完成此操作。这将过滤掉
    100101102
    ,而OP希望保留
    101102
    ?@allo_man
    let
    将给我一个阈值,但我不太确定如何将其应用到群组。KingKing我不完全清楚这里的要求,但从我收集的信息来看ed OP只想在所有特定于域的电子邮件总数低于总计数的20%时返回分组。Users=g.Take(userCount)。ToList()@allo_man OP的代码确认了我的问题,因此将更新
    let
    。可能通过添加let userCount=db.Users.count()*0.2您可以在不点击两次db的情况下完成此操作。这将过滤掉
    100101102
    ,而OP希望保留
    101102
    ?@allo_man
    let
    将给我一个阈值,但我不太确定如何将其应用到群组。KingKing我不完全清楚这里的要求,但从我收集的信息来看ed OP只想在所有特定于域的电子邮件总数低于总计数的20%时返回分组。Users=g.Take(userCount)。ToList()@allo_man OP的代码确认了我的问题,因此,
    就是要走的路,将会更新。