【问题标题】:Complicated Linq Query复杂的 Linq 查询
【发布时间】:2013-10-01 22:40:18
【问题描述】:

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

我需要做以下事情:

  1. 按域名对所有电子邮件进行分组(所有电子邮件都已小写)。
  2. 从所有组中选择所有电子邮件,其中域的电子邮件总和不超过步骤 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();
        }
    }

有人知道更好的制作方法吗?

【问题讨论】:

  • 看起来您只是想以某种方式过滤所有结果,而分组只是实现这一目标的垫脚石?顺便说一句,您能否更清楚地说明为什么101,102 而不是100,101104,105 相同但不是103,104?从下往上收集物品?
  • 您能否确认是否要完全排除某个域,如果它的总数超过总数,或者您是否想要包含所有达到阈值的电子邮件?
  • 我只需要把所有的邮件都拿到门槛
  • @KonstantinFedoseev 你检查过我的解决方案了吗?如果它不起作用,请留下一些评论让我知道,我想知道它是如何不起作用的。

标签: c# .net linq


【解决方案1】:

如果不至少两次访问数据库,我想不出一种方法,一次用于分组,一次用于总体计数,您可以尝试类似

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));

【讨论】:

  • 也许通过添加 let userCount = db.Users.Count() * 0.2 你可以做到这一点而无需两次击中 db
  • 这将过滤掉100,101,102,而OP想要保留101,102
  • @allo_man a let 会给我一个阈值,但我不太确定如何将其应用于组。 KingKing 我对这里的要求并不完全清楚,但根据我收集的信息,如果所有 特定域 电子邮件的总和低于总数的 20%,OP 只想返回分组。跨度>
  • 用户 = g.Take(userCount).ToList()
  • @allo_man OP 的代码证实了我的问题,所以let 是要走的路,会更新。
【解决方案2】:

假设要获取每个组中升序排列的最后一项:

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

【讨论】:

    【解决方案3】:
    var maxCount = db.Users.Count() * 0.2;
    var query = (from u in db.Users
            group u by u.Email.Split('@')[1] into g
            select new 
            {
                Domain = g.Key,
                Users = g.Take(maxCount).ToList()
            })
            .SelectMany(x => x.Users);
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-02-08
      • 2014-02-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多