我正在为Linq的GroupBy苦苦挣扎。我想我无法用一种表达方式做到这一点,但不知道如何解决问题。
我有以下2个课程:
public class Shipment {
public string PortOfOrigin{get;set;}
public string PortOfDestination{get;set;}
public ICollection<Invoice> Invoices{get;set;}
}
public class Invoice{
public string InvoicePeriod {get;set;}
public decimal Amount {get;set;}
}
我有一组托运,所有托运都有一个托收。这是一个例子。
List<Shipment> shipments = new List<Shipment>
{
new Shipment { PortOfOrigin = "USLOS", PortOfDestionation = "UKLON",
Invoices = new List<Invoice>
{
new Invoice{InvoicePeriod = "201106", Amount = 1000},
new Invoice{InvoicePeriod = "201106", Amount = 2000},
new Invoice{InvoicePeriod = "201107", Amount = 1000}
}
},
new Shipment { PortOfOrigin = "USLOS", PortOfDestionation = "UKLON",
Invoices = new List<Invoice>
{
new Invoice{InvoicePeriod = "201106", Amount = 3000},
new Invoice{InvoicePeriod = "201107", Amount = 2000}
}
},
new Shipment { PortOfOrigin = "USDAL", PortOfDestionation = "UKLON",
Invoices = new List<Invoice>
{
new Invoice{InvoicePeriod = "201106", Amount = 3000}
}
}
};
现在我想按以下分组:
Shipment.PortOfOrigin,Shipment.PortOfDestionation,Shipment.Invoices.InvoicePeriod。
所以我想要这样的结果
PortOfOrigin PortOfDestination InvoicePeriod Amount
------------------------------------------------------------------------
USLOS UKLON 201106 6000
USLOS UKLON 201107 3000
USDAL UKLON 201106 3000
甚至有可能在我要在Invoices.InvoicePeriod上分组的地方进行这样的分组?
UPDATE:我已经更新了答案,以包括发货数量。这要求货件具有ID字段。
以下将解决问题:
//first flatten the data so it's easier to manipulate
var query = from s in shipments
from i in s.Invoices
select new
{
s.ShipmentUniqueIdentifier,
s.PortOfOrigin,
s.PortOfDestination,
i.InvoicePeriod,
i.Amount
};
//group the data as desired
var grouping = query.GroupBy(q => new { q.PortOfOrigin, q.PortOfDestination, q.InvoicePeriod });
//finally sum the amounts
var results = from g in grouping
select new
{
g.Key.PortOfOrigin,
g.Key.PortOfDestination,
g.Key.InvoicePeriod,
Amount = g.Select(s => s.Amount).Sum(),
NumberOfShipments = g.Select(s => s.ShipmentUniqueIdentifier).Distinct().Count()
};
这是输出:
UPDATE:如所保证的,这是一个完整的工作示例:
public class Shipment {
public Guid ShipmentUniqueIdentifier{get;set;}
public string PortOfOrigin{get;set;}
public string PortOfDestination{get;set;}
public ICollection<Invoice> Invoices{get;set;}
}
public class Invoice {
public string InvoicePeriod {get;set;}
public decimal Amount {get;set;}
}
List<Shipment> shipments = new List<Shipment>
{
new Shipment { PortOfOrigin = "USLOS", PortOfDestination = "UKLON", ShipmentUniqueIdentifier = Guid.NewGuid(),
Invoices = new List<Invoice>
{
new Invoice{InvoicePeriod = "201106", Amount = 1000},
new Invoice{InvoicePeriod = "201106", Amount = 2000},
new Invoice{InvoicePeriod = "201107", Amount = 1000}
}
},
new Shipment { PortOfOrigin = "USLOS", PortOfDestination = "UKLON", ShipmentUniqueIdentifier = Guid.NewGuid(),
Invoices = new List<Invoice>
{
new Invoice{InvoicePeriod = "201106", Amount = 3000},
new Invoice{InvoicePeriod = "201107", Amount = 2000}
}
},
new Shipment { PortOfOrigin = "USDAL", PortOfDestination = "UKLON", ShipmentUniqueIdentifier = Guid.NewGuid(),
Invoices = new List<Invoice>
{
new Invoice{InvoicePeriod = "201106", Amount = 3000}
}
}
};
void Main()
{
//first flatten the data so it's easier to manipulate
var query = from s in shipments
from i in s.Invoices
select new
{
s.ShipmentUniqueIdentifier,
s.PortOfOrigin,
s.PortOfDestination,
i.InvoicePeriod,
i.Amount
};
//group the data as desired
var grouping = query.GroupBy(q => new { q.PortOfOrigin, q.PortOfDestination, q.InvoicePeriod });
//finally sum the amounts
var results = from g in grouping
select new
{
g.Key.PortOfOrigin,
g.Key.PortOfDestination,
g.Key.InvoicePeriod,
Amount = g.Select(s => s.Amount).Sum(),
NumberOfShipments = g.Select(s => s.ShipmentUniqueIdentifier).Distinct().Count()
};
//output the results
results.Dump();
}