C# LINQ 查询按条件对行求和并添加到现有列表
C# LINQ query to sum rows by condition and add to existing list
我有以下数据列表。
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 添加一行唱片类型。有时可能会有 2 或 4 个资产 类,就像您在示例 snip
中看到的那样
最终结果应该是这样的。
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 查询吗?或者我应该使用传统的 for 循环方法?
要求有点奇怪,但前提是 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
在所有可能的情况下,还有其他方法可以做到这一点
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 result;
}
}
}
我认为这段代码可以帮助您解决问题,
我在代码的第一部分使用了 LINQ,在代码的最后部分我无法避免使用 foreach。
我有以下数据列表。
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 添加一行唱片类型。有时可能会有 2 或 4 个资产 类,就像您在示例 snip
中看到的那样最终结果应该是这样的。
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 查询吗?或者我应该使用传统的 for 循环方法?
要求有点奇怪,但前提是 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
在所有可能的情况下,还有其他方法可以做到这一点
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 result;
}
}
}
我认为这段代码可以帮助您解决问题, 我在代码的第一部分使用了 LINQ,在代码的最后部分我无法避免使用 foreach。