tags:

views:

39

answers:

4

Given this structure..

I basically want to be able to take a list of items with multiple types, and create a new list that condenses down the sum of the values of each like-type. However the names of the types are dynamic (they may or may not have a specific order, and there is no finite list of them)

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

class Item
{
    public ItemType Type;
    public int Value;

    public int Add(Item item)
    {
        return this.Value + item.Value;
    }
}

class ItemType
{
    public string Name;
}

class Test
{
    public static void Main()
    {
        List<ItemType> types = new List<ItemType>();
        types.Add(new ItemType { Name = "Type1" });
        types.Add(new ItemType { Name = "Type2" });
        types.Add(new ItemType { Name = "Type3" });

        List<Item> items = new List<Item>();

        for (int i = 0; i < 10; i++)
        {
            items.Add(new Item
            {
                Type = types.Single(t => t.Name == "Type1"),
                Value = 1
            });
        }

        for (int i = 0; i < 10; i++)
        {
            items.Add(new Item
            {
                Type = types.Single(t => t.Name == "Type2"),
                Value = 1
            });
        }

        for (int i = 0; i < 10; i++)
        {
            items.Add(new Item
            {
                Type = types.Single(t => t.Name == "Type3"),
                Value = 1
            });
        }

        List<Item> combined = new List<Item>();

        // create a list with 3 items, one of each 'type', with the sum of the total values of that type.
        // types included are not always known at runtime.
    }
}
A: 

It seems to me like you are trying to get a list of Types along with their count (since Value will always be 1 in your example). Below is some code that should do this:

from i in items
group i by i.Type into t
select new { t.Key, TypeCount = t.Count() }

This would return 3 objects (displayed in table form below):

Type      TypeCount
--------  ---------
Type1     10
Type2     10
Type3     10

If value is always going to be one then I believe it's the same as just getting the count.

Abe Miessler
No, Value will not always be 1. I just used a simple value for the sake of example. Value will be its own specific object, which is what is added with the "Add" method that all ancestors inherit.
Stacey
Ahh ok, I'd go with @jarrett's solution then.
Abe Miessler
+4  A: 

Something like this should work. Warning: I didn't compile this.

items.GroupBy(i => i.Name)
   .Select(g => new Item { Type= g.First().Name, Value = g.Sum(i => i.Value)})
   .ToList()
jarrett
Thanks. This is the query I asked for, though I wasn't specific enough for my problem. I still need to figure out how to invoke the "add" method, since it doesn't exist in the abstract base class, but in the inheritors...
Stacey
You are absolutely awesome in every way. Your answer helped me towards my final solution. You may see it at http://stackoverflow.com/questions/3712326/adding-elements-together-across-inherited-arrays-linq/3718177#3718177
Stacey
A: 
List<Item> combined = items.GroupBy(i => i.Type).Select(g => new Item { Type = g.Key, Value = g.Sum(i => i.Value) }).ToList();
Albin Sunnanbo
A: 
var itemsByType = items.ToLookup(i => i.Type);
var sums = from g in itemsByType
           select new Item {
               Type = g.Key,
               Value = g.Sum(i => i.Value)
           };
var sumList = sums.ToList();
StriplingWarrior