Is there a better way to do this, perhaps replacing the for / foreach loop with something LINQ ish?

I have a list of existing Holdings, and I want to merge Holdings into another list. I know that using foreach for loops is a bad way, but I can't think of a good way to use LINQ to trim this.

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";
}
+3
source share
5 answers

The presence of the mutate function in the source list makes it very non-Linq, so here is a version that treats both lists as immutable:

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();
}

Definitely would not win a performance competition, but I like its simplicity. The following is likely to be faster, but more complex, and requires you to override the equality in Holdings to compare Sectors or create IEqualityComparer<Holding>:

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;
};
+1

, , i.e

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";
}

,

List<Holding> temp1 = new List<Holding>();
List<Holding> temp2 = new List<Holding>();
//add here to temp1 and temp2
//then...
temp1.CombineHoldings(temp2);

static 'this' ,

, , , , , -

private static void CombineHoldings(this List<Holding> existingHoldings, List<Holding> holdingsToAdd)
0

, - :

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 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);
    }
}

, , . .

0

, foreach, , , , ?

, , Holdings List SortedList, T - . . , , 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";
    }
}

O (m * log n + n), n - Holdings, m - holdingsToAdd. , existingHoldings , .

. / existingHoldings, SortedDictionary, (SortedList /)

: , LINQ , . , LINQ, holdingsToAdd, Holdings, Holdings, , Percentage, holdingsToAdd, existingHoldings, . - O (2 * m * log n + n). , .

0

, . MSDN.

(LINQ)

Found this link from another question https://stackoverflow.com/a/9746336/1278872

0
source

All Articles