C# 有没有更好的方法来实现这一点,或者用LINQ-ish的东西替换for/foreach循环?

C# 有没有更好的方法来实现这一点,或者用LINQ-ish的东西替换for/foreach循环?,c#,linq,for-loop,C#,Linq,For Loop,我有一个现有持股清单,我想合并到另一个持股清单中。我知道使用foreach&for循环是一种不好的方法,但我想不出一种使用LINQ来减少这种情况的好方法 private void CombineHoldings(List<Holding> holdingsToAdd, ref List<Holding> existingHoldings) { foreach (Holding holdingToAdd in holdingsToAdd) {

我有一个现有持股清单,我想合并到另一个持股清单中。我知道使用foreach&for循环是一种不好的方法,但我想不出一种使用LINQ来减少这种情况的好方法

private void CombineHoldings(List<Holding> holdingsToAdd, ref List<Holding> existingHoldings)
{
    foreach (Holding holdingToAdd in holdingsToAdd)
    {
        Boolean found = false;
        for (int i = 0; i < existingHoldings.Count; i++)
        {
            if (existingHoldings[i].Sector == holdingToAdd.Sector)
            {
                found = true;
                existingHoldings[i].Percentage += holdingToAdd.Percentage;
            }
        }
        if (!found)
            existingHoldings.Add(holdingToAdd);
    }
    foreach (Holding holding in existingHoldings)
        holding.Fund = "Combined Funds";
}
private void组合持股(列表持股待添加,参考列表现有持股)
{
foreach(HoldingHoldingLoaded in holdingToAdd)
{
布尔值=false;
for(int i=0;i
如果您经常在列表中调用此方法,那么我建议将其放入列表类型的扩展方法中,即

private static void CombineHoldings(this List<Holding> holdingsToAdd, ref List<Holding> existingHoldings)
{
    foreach (Holding holdingToAdd in holdingsToAdd)
    {
        Boolean found = false;
        for (int i = 0; i < existingHoldings.Count; i++)
        {
            if (existingHoldings[i].Sector == holdingToAdd.Sector)
            {
                found = true;
                existingHoldings[i].Percentage += holdingToAdd.Percentage;
            }
        }
        if (!found)
            existingHoldings.Add(holdingToAdd);
    }
    foreach (Holding holding in existingHoldings)
        holding.Fund = "Combined Funds";
}
private static void组合持股(此列表持股待添加,参考列表现有持股)
{
foreach(HoldingHoldingLoaded in holdingToAdd)
{
布尔值=false;
for(int i=0;i
这将允许您在创建列表的任何地方

List<Holding> temp1 = new List<Holding>();
List<Holding> temp2 = new List<Holding>();
//add here to temp1 and temp2
//then...
temp1.CombineHoldings(temp2);
List temp1=新列表();
List temp2=新列表();
//将此处添加到temp1和temp2
//然后。。。
temp1.组合持股(temp2);
将第一个方法设置为静态,并在第一个参数前面放置一个“this”关键字,这意味着它将扩展该类型

尽管切换这两个参数可能更有意义,但是查看参数后,它会像这样添加到调用方法的列表中-

private static void CombineHoldings(this List<Holding> existingHoldings, List<Holding> holdingsToAdd)
私有静态无效组合持股(此列表现有持股,列表持股待添加)

我可能会这样说:

private void CombineHoldings(List<Holding> holdingsToAdd, ref List<Holding> existingHoldings)
{
    // group the new holdings by sector
    var groupedHoldings = holdingsToAdd.GroupBy(h => h.Sector);

    // now iterate over the groupings
    foreach(var group in groupedHoldings) {
         // calculate the sum of the percentages in the group
         // we'll need this later
         var sum = group.Sum(h => h.Percentage);

         // get the index of a matching object in existing holdings
         var existingHoldingIndex = existingHoldings.FindIndex(h => h.Sector == group.Key);

         // yay! found one. add the sum of the group and our job's done.
         if(existingHoldingIndex >= 0) {
             existingHoldings[existingHoldingIndex].Percentage += sum;
             continue;
         }

         // didn't find one, so take the first holding in the group, set its percentage to the sum
         // and append that to the existing holdings table
         var newHolding = group[0];
         newHolding.Percentage = sum;

         existingHoldings.Add(newHolding);
    }
}
private void组合持股(列表持股待添加,参考列表现有持股)
{
//按行业对新持有的股份进行分组
var groupedHoldings=持有至附加GroupBy(h=>h.Sector);
//现在迭代分组
foreach(groupedHoldings中的var组){
//计算组中百分比的总和
//我们以后需要这个
var sum=组和(h=>h.Percentage);
//获取现有资源中匹配对象的索引
var existingholdindex=existingHoldings.FindIndex(h=>h.Sector==group.Key);
//耶!找到一个。加上小组的总数,我们的工作就完成了。
如果(existingHoldingIndex>=0){
现有持有量[existingHoldingIndex]。百分比+=总和;
继续;
}
//找不到一个,所以取组中的第一个持股,将其百分比设置为总和
//并将其附加到现有的holdings表中
var newHolding=组[0];
新控股。百分比=总和;
现有控股。添加(新控股);
}
}

就性能而言,我不确定这是否有效。但它似乎更优雅。

您的问题有点含糊不清,您想摆脱foreach循环,是因为您觉得有太多的循环,还是因为您想要更好的性能

假设这是一个关于提高绩效的问题,我建议将现有持股从列表更改为a,其中T是Holding.Sector的类型。为了获得最佳性能,扇区应该是一个类似int的

private void CombineHoldings(List<Holding> holdingsToAdd, SortedList<int,Holding> existingHoldings) //Remove ref since List and SortedList are reference types and we are not changing the pointer.
{

    for (int i = 0; i < holdingsToAdd.Count; i++)
    {
        if (existingHoldings.ContainsKey(holdingsToAdd[i].Sector))
        {
            existingHoldings[holdingsToAdd[i].Sector].Percentage += holdingsToAdd[i].Percentage;
        }
        else
        {
            existingHoldings.Add(holdingsToAdd[i].Sector, holdingsToAdd[i]);
        }
    }
    for (int i = 0; i < existingHoldings.Count; i++)
    {
        existingHoldings.Values[i].Fund = "Combined Funds";
    }
}
private void CombineHoldings(List holdingsToAdd,SortedList existingHoldings)//删除ref,因为List和SortedList是引用类型,我们不会更改指针。
{
for(int i=0;i
此方法将产生一个O(m*logn+n),其中n是现有Holdings中的元素数,m是holdingsToAdd中的元素数。不幸的是,所有现有的Holdings元素都必须更新其基金价值,因为它增加了对该集合的额外传递

注意:如果您不断地从现有控股中添加/删除项目,那么您可以使用更快的(SortedList访问元素更快,但添加/删除所需的时间更长)


编辑:请务必注意,LINQ用于搜索集合,而不是更新集合。因此,您可以使用LINQ查找现有控股中存在和不存在的holdingsToAdd,然后通过现有控股循环设置基金,如果需要设置百分比,但是需要对holdingsToAdd和existingHoldings进行排序,并且您仍将通过每个集合循环一次。它的数量级为O(2*m*logn+n)。编译器可能能够将两个查询合并到一个调用中,但即使这样,您也会看到类似的性能,可读性较差。

让函数对原始列表进行变异会使其非常非Linq,因此以下版本将两个列表视为不可变:

private List<Holding> CombineHoldings(
    List<Holding> holdingsToAdd, 
    List<Holding> existingHoldings) 
{
    var holdings = existingHoldings.Concat(holdingsToAdd)
        .GroupBy(h => h.Sector)
        .Select(g => 
        { 
            var result = g.First(); 
            result.Percentage = g.Select(h => h.Percentage).Sum();
            return result; 
        });
    return holdings.ToList();
}
私有列表组合持有者(
要添加的列表保持,
列出现有股份)
{
var holdings=existingHoldings.Concat(holdingsToAdd)
private List<Holding> CombineHoldings(
    List<Holding> holdingsToAdd, 
    List<Holding> existingHoldings) 
{
    var holdings = existingHoldings.GroupJoin(holdingsToAdd, h => h, h => h, 
        (h, toAdd) =>
        new Holding(
            h.Sector, 
            /*Other parameters to clone*/, 
            h.Percentage + toAdd.Select(i => i.Percentage).Sum())
        ).ToList();
    holdings.AddRange(holdingsToAdd.Except(holdings));
    return holdings;
};