asp.net C# Linq 查询检索列中每个值的总和

发布于 2024-12-11 15:23:07 字数 1964 浏览 0 评论 0原文

我有以下 TrackerReport 对象数组:

public class TrackerReport : TrackerMilestone
{
    public long Views { get; set; }

    public override string ToString()
    {
        return "Id=" + MilestoneId + " | Name=" + Name + " | Views = " + Views;
}

我还发布了父类以更好地解释:

public class TrackerMilestone
{
    public int MilestoneId { get; set; }
    public int CampaignId { get; set; }       
    public string Name { get; set; }
    public int? SortIndex { get; set; }
    public string Url { get; set; }
    public bool IsGoal { get; set; }
    public bool IsPartialGoal { get; set; }
    public int? ParentMilestoneId { get; set; }
    public int? ViewPercent { get; set; }

    public override string ToString()
    {
        return "Id=" + MilestoneId + " | Name=" + Name + " | Url = " +  Url;
    }
}

以便它或多或少地显示为这样:

ID    Name    Url    Counter
1      A     ab.com     5
2      N     ac.com     2

并且我有一个以这种方式填充的该对象的列表:

var trackerReportList = new List<TrackerReport[]>();
foreach (var trackerItem in trackerChildren)
{
    //currentReport is the array of TrackerReport TrackerReport[] above mentioned
    var currentReport = GetReportForItem(GetFromDate(), GetToDate(), trackerItem.ID,
                                                 FindCampaignId(trackerItem));
    trackerReportList.Add(currentReport);    
}

所有条目都有相同的值,但计数器,因此,例如:
list1:

ID    Name    Url    Counter
1      A     ab.com     5
2      N     ac.com     2

list2:

ID    Name    Url    Counter
1      A     ab.com     17
2      N     ac.com     28

我的目标是生成一个 TrackerReport[],并将计数器值的总和作为计数器。

TrackerReport[]:

ID    Name    Url    Counter
1      A     ab.com     22
2      N     ac.com     30

是否有任何 Linq 查询可以执行此操作?或者如果您想出更好的解决方案,只需发布​​即可。

提前致谢!

I have the following array of TrackerReport Object:

public class TrackerReport : TrackerMilestone
{
    public long Views { get; set; }

    public override string ToString()
    {
        return "Id=" + MilestoneId + " | Name=" + Name + " | Views = " + Views;
}

I post also the parent class to better explain:

public class TrackerMilestone
{
    public int MilestoneId { get; set; }
    public int CampaignId { get; set; }       
    public string Name { get; set; }
    public int? SortIndex { get; set; }
    public string Url { get; set; }
    public bool IsGoal { get; set; }
    public bool IsPartialGoal { get; set; }
    public int? ParentMilestoneId { get; set; }
    public int? ViewPercent { get; set; }

    public override string ToString()
    {
        return "Id=" + MilestoneId + " | Name=" + Name + " | Url = " +  Url;
    }
}

So that it is displayed like this more or less:

ID    Name    Url    Counter
1      A     ab.com     5
2      N     ac.com     2

And I have a List of this object that I fill in this way:

var trackerReportList = new List<TrackerReport[]>();
foreach (var trackerItem in trackerChildren)
{
    //currentReport is the array of TrackerReport TrackerReport[] above mentioned
    var currentReport = GetReportForItem(GetFromDate(), GetToDate(), trackerItem.ID,
                                                 FindCampaignId(trackerItem));
    trackerReportList.Add(currentReport);    
}

All the entries have the same values, but the counter, so, for ex:
list1:

ID    Name    Url    Counter
1      A     ab.com     5
2      N     ac.com     2

list2:

ID    Name    Url    Counter
1      A     ab.com     17
2      N     ac.com     28

My goal is to generate a single TrackerReport[], with the sum of the counter values as counter.

TrackerReport[]:

ID    Name    Url    Counter
1      A     ab.com     22
2      N     ac.com     30

Is there any Linq query to do this? Or If you come up with a better solution, just post it.

Thanks in advance!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

若沐 2024-12-18 15:23:07

以下是如何使用 Linq 来完成此操作。

  1. 首先,您希望获取单个列表中的数据,而不是ArraysList。我们可以使用 SelectMany 来做到这一点。

    trackerReportList.SelectMany(c => c)List() 扁平化为 IEnumerable< /p>

  2. 然后您按相关列对对象进行分组

    将 p 按 new { 分组
                ID = p.MilestoneId, 
                姓名 = p.姓名,
                Url = p.Url} 转换为 g
    
  3. 最后,将分组投影为我们想要的格式。 Counter 是通过为每个分组中的对象集合添加 Views 来获得的。

    选择新{
        ...
    };
    

把它们放在一起:

var report = from p in trackerReportList.SelectMany(c => c) 
             group p by new {
                ID = p.MilestoneId, 
                Name = p.Name,
                Url = p.Url} into g
             select new {
                ID = g.Key.ID,
                Name = g.Key.Name,
                Url = g.Key.Url,
                Counter = g.Sum(c => c.Views)
            };

Here's how to do it using Linq.

  1. Firstly, you want to get the data in a single list rather than a List of Arrays. We can do this with a SelectMany.

    trackerReportList.SelectMany(c => c) flattens List<TrackerReport[]>() into IEnumerable<TrackerReport>

  2. Then you group the objects by the relevant column/columns

    group p by new {
                ID = p.MilestoneId, 
                Name = p.Name,
                Url = p.Url} into g
    
  3. Finally, you project the grouping into the format we want. Counter is obtained by Adding the Views for the collection of objects in each grouping.

    select new {
        ...
    };
    

Putting it all together:

var report = from p in trackerReportList.SelectMany(c => c) 
             group p by new {
                ID = p.MilestoneId, 
                Name = p.Name,
                Url = p.Url} into g
             select new {
                ID = g.Key.ID,
                Name = g.Key.Name,
                Url = g.Key.Url,
                Counter = g.Sum(c => c.Views)
            };
恋你朝朝暮暮 2024-12-18 15:23:07

这是您的查询的lambda 表达式

TrackerReport[] trackerInfoList = trackerReportList
    .SelectMany(s => s)
    .GroupBy(g => g.MilestoneId)
    .Select(s =>
                {
                    var trackerReportCloned = Clone<TrackerReport[]>(s.First());
                    trackerReportCloned.Views = s.Sum(su => su.Views);
                    return trackerReportCloned;
                })
    .ToArray();

如果您已经注意到,我已经使用 Clone(T) 方法通过分组值深度克隆一个对象。我本来可以通过复制每个属性来完成,但我发现这是最简单的。

这是 Clone() 方法:

public static T Clone<T>(T source)
{
    if (!typeof(T).IsSerializable)
    {
        throw new ArgumentException("The type must be serializable.", "source");
    }

    // Don't serialize a null object, simply return the default for that object
    if (Object.ReferenceEquals(source, null))
    {
        return default(T);
    }

    IFormatter formatter = new BinaryFormatter();
    Stream stream = new MemoryStream();
    using (stream)
    {
        formatter.Serialize(stream, source);
        stream.Seek(0, SeekOrigin.Begin);
        return (T)formatter.Deserialize(stream);
    }
}

在继续之前,您需要在 DTO 对象上设置 [Serializing] 属性。

[Serializable]
public class TrackerReport : TrackerMilestone
{
    .
    .
    .
}

[Serializable]
public class TrackerMilestone
{
    .
    .
    .
}

希望,这就是您正在寻找的。

This is the lambda expression for your query.

TrackerReport[] trackerInfoList = trackerReportList
    .SelectMany(s => s)
    .GroupBy(g => g.MilestoneId)
    .Select(s =>
                {
                    var trackerReportCloned = Clone<TrackerReport[]>(s.First());
                    trackerReportCloned.Views = s.Sum(su => su.Views);
                    return trackerReportCloned;
                })
    .ToArray();

If you have noted, I have used Clone<T>(T) method to deep cloning one object by the grouped value. I could have done by copying each property, but I found it the easiest.

This is the Clone() method:

public static T Clone<T>(T source)
{
    if (!typeof(T).IsSerializable)
    {
        throw new ArgumentException("The type must be serializable.", "source");
    }

    // Don't serialize a null object, simply return the default for that object
    if (Object.ReferenceEquals(source, null))
    {
        return default(T);
    }

    IFormatter formatter = new BinaryFormatter();
    Stream stream = new MemoryStream();
    using (stream)
    {
        formatter.Serialize(stream, source);
        stream.Seek(0, SeekOrigin.Begin);
        return (T)formatter.Deserialize(stream);
    }
}

Before you continue, you need to set [Serializable] attribute on your DTO objects.

[Serializable]
public class TrackerReport : TrackerMilestone
{
    .
    .
    .
}

[Serializable]
public class TrackerMilestone
{
    .
    .
    .
}

Hope, this is what you are looking for.

蓝海似她心 2024-12-18 15:23:07

我会按以下方式进行:
1) 让 TrackerReports[] resultListtrackerReportList[0] 项的深层副本数组
2)据我了解,Views属性对应于Counter列。如果是这样,那么

foreach(report in resultList)
{
    report.Views = trackerReportList.Sum(reports => reports.Single(r => r.MilestoneId == report.MilestoneId).Views);
}

I'd do it in the following way:
1) Let the TrackerReports[] resultList is the array of deep copies of the trackerReportList[0] items
2) As I understand, the Views property corresponds to the Counter column. If so, then

foreach(report in resultList)
{
    report.Views = trackerReportList.Sum(reports => reports.Single(r => r.MilestoneId == report.MilestoneId).Views);
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文