Answer seems to have two parts.
If the DataTables are generated 'in memory' you have to use LINQ
Dim t = (From totals In (allocated.AsEnumerable.Union(spent.AsEnumerable)) _
Group totals By accCategory = totals.Item("accCategory"), ID = totals.Item("ID"), Account = totals.Item("Account") _
Into g = Group _
Select New With {Key .accCategory = accCategory, Key .ID = ID, Key .Account = Account, Key .Jan = g.Sum(Function(totals) If(IsDBNull(totals.Item("Jan")), 0, CDec(totals.Item("Jan"))))}).ToList
You then have to convert it back to a table (if you want to bind it to a DataGrid for example)
Public Function ToTable(Of T)(data As IList(Of T)) As DataTable
Dim properties As PropertyDescriptorCollection = TypeDescriptor.GetProperties(GetType(T))
Dim table As New DataTable()
For Each prop As PropertyDescriptor In properties
table.Columns.Add(prop.Name, If(Nullable.GetUnderlyingType(prop.PropertyType), prop.PropertyType))
Next
For Each item As T In data
Dim row As DataRow = table.NewRow()
For Each prop As PropertyDescriptor In properties
row(prop.Name) = If(prop.GetValue(item), DBNull.Value)
Next
table.Rows.Add(row)
Next
Return table
End Function
The only outstanding issue is Null (DBNull) handling - but I'll post a separate question.
Andy