Запрос C# LINQ для суммирования строк по условию и добавления в существующий список

#c# #linq #linq-to-sql

Вопрос:

У меня есть следующий список данных.

  var data = new List<SummaryTabData>()
        {
            new SummaryTabData(){ LP = "LP_1", assetClass = "Asset_CFD_Long", avgSlippagePts = 54.23} ,
            new SummaryTabData(){ LP = "LP_1", assetClass = "Asset_FX_Long", avgSlippagePts = 61.41} ,
            new SummaryTabData(){ LP = "LP_1", assetClass = "Asset_FX_Short", avgSlippagePts = 11.48} ,
            new SummaryTabData(){ LP = "LP_1", assetClass = "Asset_CFD_Short", avgSlippagePts = 63.51} ,

            new SummaryTabData(){ LP = "LP_2", assetClass = "Asset_FX_Long",  avgSlippagePts = 6.51} ,            
            new SummaryTabData(){ LP = "LP_2", assetClass = "Asset_FX_Short", avgSlippagePts = 13.51}
        };
 

Моя цель-добавить дополнительную строку для каждой пары Asset_CFD_long/Asset_CFD_short и Asset_FX_Long/Asset_FX_Short для каждого типа LP. Иногда может быть либо 2, либо 4 класса активов, как вы можете видеть в примере снипа

Конечный результат должен выглядеть примерно так.

 var data = new List<SummaryTabData>()
            {
                new SummaryTabData(){ LP = "LP_1", assetClass = "Asset_CFD_Long", avgSlippagePts = 54.23} ,
                new SummaryTabData(){ LP = "LP_1", assetClass = "Asset_CFD_Short", avgSlippagePts = 63.51} ,

                // that is the new row added to the collection for LP_1 CFD
                new SummaryTabData(){ LP = "LP_1", assetClass = "CFD_Total", avgSlippagePts = 117.74} ,

                new SummaryTabData(){ LP = "LP_1", assetClass = "Asset_FX_Long", avgSlippagePts = 61.41} ,
                new SummaryTabData(){ LP = "LP_1", assetClass = "Asset_FX_Short", avgSlippagePts = 11.48} ,

                // that is the new row added to the collection for LP_1 FX
                new SummaryTabData(){ LP = "LP_1", assetClass = "FX_Total", avgSlippagePts = 72.89} ,

                new SummaryTabData(){ LP = "LP_2", assetClass = "Asset_FX_Long",  avgSlippagePts = 6.51} ,
                new SummaryTabData(){ LP = "LP_2", assetClass = "Asset_FX_Short", avgSlippagePts = 13.51},

                // that is the new row added to the collection for LP_2 FX
                new SummaryTabData(){ LP = "LP_2", assetClass = "FX_Total", avgSlippagePts = 20.02},
            };
 

Данные не сортируются. Вы знаете, для какого-то запроса LINQ, который может это сделать, или мне следует использовать традиционный подход для цикла ?

Комментарии:

1. Это требование немного странное. однако я не осуждаю. по сути, вы захотите Groupby затем Sum повторить результаты, затем вернуться к списку и найти последнее вхождение каждой группы, а затем вставить.

2. @TheGeneral не могли бы вы предоставить фрагмент кода ?

3. Если он не отсортирован, как вы узнаете, какие два элемента следует соединить вместе?

Ответ №1:

Требования немного странные, однако предполагается, что группы LP можно заказать любым способом

Обновленный

 var groups = data
   .Select(x => new { Asset = x.assetClass.Split("_")[1], Summary = x })
   .GroupBy(x => new { x.Asset, x.Summary.LP });

var list = new List<SummaryTabData>();

foreach (var group in groups)
{
   list.AddRange(group.Select(x => x.Summary).ToList());

   list.Add(new SummaryTabData()
   {
      assetClass = $"{group.Key.Asset}_Total",
      LP = group.Key.LP,
      avgSlippagePts = group.Sum(x => x.Summary.avgSlippagePts)
   });

}

foreach (var item in list)
   Console.WriteLine($"{item.LP}, {item.assetClass}, {item.avgSlippagePts}");
 

Выход

 LP_1, Asset_FX_Short, 11.48
LP_1, Asset_FX_Long, 61.41
LP_1, FX_Total, 72.89
LP_1, Asset_CFD_Short, 63.51
LP_1, Asset_CFD_Long, 54.23
LP_1, CFD_Total, 117.74
LP_2, Asset_FX_Short, 13.51
LP_2, Asset_FX_Long, 6.51
LP_2, FX_Total, 20.02
 

По всей вероятности, есть и другие способы сделать это

Полная Демонстрация Здесь

Ответ №2:

 using System;
using System.Collections.Generic;using System.Linq;

namespace TestConsoleApp
{
    class Program
    {
        public class SummaryTabData
        {
            public string LP { get; set; }
            public string assetClass { get; set; }
            public double avgSlippagePts { get; set; }
        }

        public enum AssetClassType
        {
            Cfd,
            Fx
        }

        static void Main(string[] args)
        {

            var data = new List<SummaryTabData>()
            {
                new SummaryTabData(){ LP = "LP_1", assetClass = "Asset_CFD_Long", avgSlippagePts = 54.23} ,
                new SummaryTabData(){ LP = "LP_1", assetClass = "Asset_FX_Long", avgSlippagePts = 61.41} ,

                new SummaryTabData(){ LP = "LP_1", assetClass = "Asset_FX_Short", avgSlippagePts = 11.48} ,
                new SummaryTabData(){ LP = "LP_1", assetClass = "Asset_CFD_Short", avgSlippagePts = 63.51} ,

                new SummaryTabData(){ LP = "LP_2", assetClass = "Asset_FX_Long",  avgSlippagePts = 6.51} ,
                new SummaryTabData(){ LP = "LP_2", assetClass = "Asset_FX_Short", avgSlippagePts = 13.51}
            };
            var expectedResult = GetSummaries(data);

        }

        private static List<SummaryTabData> GetSummaries(List<SummaryTabData> data)
        {
            var datas = data.Select(x => new
            {
                x.LP,
                x.assetClass,
                x.avgSlippagePts,
                AssetClassType = x.assetClass.Contains("CFD") ? AssetClassType.Cfd : AssetClassType.Fx
            }).GroupBy(x => new { x.AssetClassType, x.LP })
                .Select(x => new
                {
                    assetClass = x.Key.AssetClassType == AssetClassType.Cfd ? "CFD_Total" : "FX_Total",
                    sum = x.Sum(z => z.avgSlippagePts),
                    Lp = x.Key.LP,
                    SummaryTabData = x.Select(z => new SummaryTabData()
                    {
                        assetClass = z.assetClass,
                        LP = z.LP,
                        avgSlippagePts = z.avgSlippagePts
                    })
                }).ToList();

            List<SummaryTabData> result = new List<SummaryTabData>();

            foreach (var groupData in datas)
            {
                result.AddRange(groupData.SummaryTabData);

                result.Add(new SummaryTabData
                {
                    assetClass = groupData.assetClass,
                    LP = groupData.Lp,
                    avgSlippagePts = groupData.sum
                });
            }

            return resu<
        }
    }
}
 

Я думаю, что этот код может помочь вам решить вашу проблему,
Я использовал LINQ для первой части кода, в последней части кода я не мог избежать использования foreach.