Reputation: 432
I have a list of objects (call them type salesItems) Lets say these items have 50 properties, with Name, price, quantity being 3 of them). I would like to know how to merge the list together combining any salesItems by name using the following logic:
If there are multiple salesOrders that have the same Name:
I would like to do with linq. I realize i could use a big for each c# loop instead.
If there are additional items in the list I would like to follow similar logic for those as well.
EX: A salesOrder list with (A,B,C,D,E)
A: Name=ball Price= 2.24 Quantity=1 (other values = bla bla)
B: Name= ball Price = 15.33 Quantity=3 (other values)
c: Name= bat Price = 22.14 Quantity=3 (other values)
D: Name= bat Price= 19.22 Quantity=2 (other values)
E: Name = ball Price=4.32 Quantity=2 (other values)
Result list I want 2 Sales orders in list (A,C) A: Name=ball Price= 2.24 Quantity=6 (other values = bla bla from a's properties) c: Name= bat Price = 22.14 Quantity=5 (other values from c's properties)
Upvotes: 2
Views: 4804
Reputation: 5715
You want linq's .GroupBy
method!!!
I've defined your class as:
public class SalesOrder
{
public string Name { get; set; }
public double Price { get; set; }
public int Quantity { get; set; }
public SalesOrder(string Name, double Price, int Quantity)
{
this.Name = Name;
this.Price = Price;
this.Quantity = Quantity;
}
}
then I have created a list of your orders like this:
List<SalesOrder> Orders = new List<SalesOrder>()
{
new SalesOrder("Ball", 2.24, 1),
new SalesOrder("Ball", 15.33, 3),
new SalesOrder("Bat", 22.14, 3),
new SalesOrder("Bat", 19.22, 2),
new SalesOrder("Ball", 4.32, 2)
};
and grouped them by the name before selecting the values you want for each group into a new instance of the SalesOrder
class like this:
List<SalesOrder> Combined_Orders = Orders
.GroupBy (o => o.Name)
.Select (o => new SalesOrder(o.Key, o.Select (x => x.Price).First(), o.Sum(x => x.Quantity)))
.ToList();
UPDATE: In response to OP's comment
As the real SalesOrder
will have hundreds of properties, you can avoid typing them all out in the linq query by adding a constructor to the SalesOrder
class that accepts the result of the group by as an argument, then do all the work in the constructor. While it doesn't stop you from having to type out all the properties, it does mean that its neatly abstracted away. Also this way it forces/enables you to decide on what to do with each of the properties (first/sum/average).
To do this you will need a second constructor that looks like this:
public SalesOrder(IGrouping<string, SalesOrder> Group)
{
this.Name = Group.Key;
this.Price = Group.First().Price;
this.Quantity = Group.Sum(g => g.Quantity);
// do all other properties here too
}
Then update the group by to look like this (note that only the result of the grouping "g" is passed into the constructor now):
List<SalesOrder> Combined_Orders = Orders
.GroupBy (o => o.Name)
.Select (g => new SalesOrder(g))
.ToList();
Upvotes: 7
Reputation: 455
Hi You can use the following code,
class SalesItem
{
public string Name { get; set; }
public int Price { get; set; }
public int Quantity { get; set; }
}
class SalesOrder
{
public void LoadItems()
{
List<SalesItem> SalesItems = new List<SalesItem>();
SalesItem salesitem = new SalesItem()
{
Name = "Ball",
Price = 12,
Quantity = 1
};
SalesItems.Add(salesitem);
salesitem = new SalesItem()
{
Name = "Ball",
Price = 36,
Quantity = 3
};
SalesItems.Add(salesitem);
salesitem = new SalesItem()
{
Name = "Bat",
Price = 50,
Quantity = 1
};
SalesItems.Add(salesitem);
salesitem = new SalesItem()
{
Name = "Ball",
Price = 84,
Quantity = 7
};
SalesItems.Add(salesitem);
salesitem = new SalesItem()
{
Name = "Bat",
Price = 150,
Quantity = 3
};
SalesItems.Add(salesitem);
GroupOrders(SalesItems);
}
public List<SalesItem> GroupOrders(List<SalesItem> SalesItems)
{
var list = from item in SalesItems
group item by item.Name into orders
select new SalesItem
{
Name = orders.Key,
Price = orders.Sum(X=>X.Price),
Quantity = orders.Sum(X=>X.Quantity)
};
List<SalesItem> resultList = new List<SalesItem>();
foreach (SalesItem saleitem in list)
{
resultList.Add(saleitem);
}
return resultList;
}
}
Upvotes: 0