【问题标题】:Linq query to group by field1, count field2 and filter by count between values of joined collectionLinq 查询按字段 1 分组,对字段 2 进行计数,并按加入集合的值之间的计数进行过滤
【发布时间】:2012-12-27 21:45:12
【问题描述】:

我无法正确获取我的 linq 查询。我一直反对用 foreach 循环来做这件事,因为我试图更好地理解 linq。

我在 LinqPad 中有以下数据。

void Main()
{
    var events = new[] {
        new {ID = 1, EventLevel = 1, PatientID = "1", CodeID = "2", Occurences = 0 },
        new {ID = 2, EventLevel = 2, PatientID = "1", CodeID = "2", Occurences = 0 },
        new {ID = 3, EventLevel = 1, PatientID = "2", CodeID = "1", Occurences = 0 },
        new {ID = 4, EventLevel = 3, PatientID = "2", CodeID = "2", Occurences = 0 },
        new {ID = 5, EventLevel = 1, PatientID = "3", CodeID = "3", Occurences = 0 },
        new {ID = 6, EventLevel = 3, PatientID = "1", CodeID = "4", Occurences = 0 }
    };

    var filter = new FilterCriterion();
    var searches = new List<FilterCriterion.Occurence>();
    searches.Add(new FilterCriterion.Occurence() { CodeID = "1", MinOccurences = 2, MaxOccurences = 3 });
    searches.Add(new FilterCriterion.Occurence() { CodeID = "2", MinOccurences = 2, MaxOccurences = 3 });

    filter.Searches = searches;

    var summary = from e in events
        let de = new
        {
            PatientID = e.PatientID,
            CodeID = e.CodeID
        }
        group e by de into t
        select new
        {
            PatientID = t.Key.PatientID,
                CodeID = t.Key.CodeID,
            Occurences = t.Count(d => t.Key.CodeID == d.CodeID)
        };

    var allCodes = filter.Searches.Select(i => i.CodeID);

    summary = summary.Where(e => allCodes.Contains(e.CodeID));

    // How do I find the original ID property from the "events" collection and how do I 
    // eliminate the instances where the Occurences is not between MinOccurences and MaxOccurences.

    foreach (var item in summary)
        Console.WriteLine(item);
}

public class FilterCriterion
{

   public IEnumerable<Occurence> Searches { get; set; }

   public class Occurence
   {
       public string CodeID { get; set; }
       public int? MinOccurences { get; set; }
       public int? MaxOccurences { get; set; }
   }

}

我遇到的问题是需要通过 MinOccurences 和 MaxOccurences 过滤器属性过滤结果,最后我想要 ID 为 1、2、3 和 4 的“事件”对象。

如果您能提供帮助,请提前感谢。

【问题讨论】:

  • 我不完全理解您的问题 - 以所需的输出为例可能会有所帮助
  • 为什么 id 是 34?它们似乎不适合最小-最大出现次数。
  • 我的错误。你是对的。我应该只取回 ID 1 和 2

标签: c# linq linq-to-objects


【解决方案1】:

要在处理结束时访问event.ID,您需要在第一个查询中传递它。将select 更改为:

// ...
group e by de into t
select new
{
    PatientID = t.Key.PatientID,
    CodeID = t.Key.CodeID,
    Occurences = t.Count(d => t.Key.CodeID == d.CodeID),
    // taking original items with us
    Items = t
};

完成后,您的最终查询(包括出现过滤器)可能如下所示:

var result = summary
    // get all necessary data, including filter that matched given item
    .Select(Item => new
        {
            Item,
            Filter = searches.FirstOrDefault(f => f.CodeID == Item.CodeID)
        })
    // get rid of those without matching filter
    .Where(i => i.Filter != null)
    // this is your occurrences filtering
    .Where(i => i.Item.Occurences >= i.Filter.MinOccurences
        && i.Item.Occurences <= i.Filter.MaxOccurences)
    // and finally extract original events IDs
    .SelectMany(i => i.Item.Items)
    .Select(i => i.ID);

这会产生12 作为结果。 34 被排除在外,因为它们没有过滤过去的事件。

【讨论】:

  • 哦,感谢您出色的解释,我现在看到了。我没有意识到我可以带走整套原始物品。您正在对 Select 语句中的匿名对象执行类似的操作,您在其中传递过滤器对象,然后链接 Where 子句以防止空对象异常。这真的很酷。非常感谢你的帮助。我现在明白了一点。
【解决方案2】:

我已经在 linqpad 中运行了你的程序。

我的理解是你想对结果数据集的出现次数使用 filter.MinOccurences 和 filter.MaxOccurences 进行过滤。

您可以使用 Where 子句添加其他过滤器。

if (filter.MinOccurences.HasValue)
 summary = summary.Where (x=> x.Occurences >= filter.MinOccurences);

if (filter.MaxOccurences.HasValue)
 summary = summary.Where (x=> x.Occurences <= filter.MaxOccurences);

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-09-27
    • 1970-01-01
    • 2021-04-19
    • 2017-03-24
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多