Linq Group By statement on a Dictionary containing a list - c#

I have a dictionary defined as
var dataDict = new Dictionary<String, List<RICData>>();
with the RICData class defined as
class RICData
{
public string pubdate { get; set; }
public string settle { get; set; }
public int colorder { get; set; }
}
The following illustrates the data the dictionary dataDict contains -
"TEST1", ("12/01/2015, 100.1, 1", "12/02/2015, 200.1, 2", "12/03/2015, 300.4, 3")
"TEST2", ("12/01/2015, 150.1, 6", "12/02/2015, 200.1, 7")
"TEST3", ("12/01/2015, 250.1, 4", "12/02/2015, 400, 5")
What I would like to do is group the data by date and order by colorder and retun something simlar to what is below
"12/01/2015", ("TEST1, 100.1, 1", "TEST3, 250.1, 4", "TEST2, 150.1, 6")
"12/02/2015", ("TEST1, 200.1, 2", "TEST3, 400, 5", "TEST2, 200.1, 7"
"12/03/2015", ("TEST1, 300.4, 3")
Here's some sample code. I guess I'm not sure how to group this data
var dataDict = new Dictionary<String, List<RICData>>();
var rdList = new List<RICData>();
rdList.Add(new RICData{pubdate = "12/01/2015", settle = "100.1", colorder = 1});
rdList.Add(new RICData{pubdate = "12/02/2015", settle = "110.1", colorder = 2});
rdList.Add(new RICData { pubdate = "12/03/2015", settle = "120.1", colorder = 3 });
dataDict.Add("TEST1", rdList);
var rdList1 = new List<RICData>();
rdList1.Add(new RICData { pubdate = "12/01/2015", settle = "140.1", colorder = 6 });
rdList1.Add(new RICData { pubdate = "12/02/2015", settle = "100.1", colorder = 7 });
dataDict.Add("TEST2", rdList1);
var rdList2 = new List<RICData>();
rdList2.Add(new RICData { pubdate = "12/01/2015", settle = "240.1", colorder = 4 });
rdList2.Add(new RICData { pubdate = "12/02/2015", settle = "200.1", colorder = 5 });
dataDict.Add("TEST3", rdList2);
//?????
var resultGrp = dataDict.GroupBy(p => p.Value.Select(x => x.pubdate));

public class RICData
{
public string PubDate { get; set; }
public string Settle { get; set; }
public int ColorDer { get; set; }
}
public class NewRICData
{
public string Label { get; set; }
public string Settle { get; set; }
public int Colorder { get; set; }
}
var oldDict = new Dictionary<string, List<RICData>>();
var newDict = oldDict.SelectMany(pair => pair.Value.Select(data => new
{
PubDate = DateTime.Parse(data.PubDate),
NewRICData = new NewRICData
{
Label = pair.Key,
Settle = data.Settle,
ColorDer = data.ColorDer
}
}))
.GroupBy(x => x.PubDate.Date)
.ToDictionary(group => group.Key.ToString("d"),
group => group.Select(x => x.NewRICData)
.OrderBy(x => x.ColorDer));

Related

Linq List problems with GroupBy and Count

Given the data below, I am trying to write a LINQ statement that will group by ListOfAdmin by id so it will only display one user. I am also checking that the count is not 0. The record one has no ListOfAdmin so that Count==0 should return null but it is displaying records for ListOfAdmin . Also
once I add //.GroupBy(f => f.id) I get the error Cannot implicitly convert type 'System.Collections.Generic.List
All of the other section is working fine.
Once I add ListOfSubscription with no record for ListOfAdmin I get the error
LINQPad Example
class Subscription
{
public int SubscriptionId { get; set; }
public int ParentProductId { get; set; }
public string ParentProductName { get; set; }
public string ChildProductName { get; set; }
public int ChildProductId { get; set; }
public int GroupId { get; set; }
public DateTime? EndDate { get; set; }
public List<admin> ListOfAdmin { get; set; }
}
class SubscriptionViewModel
{
public int SubscriptionId { get; set; }
public int ParentProductId { get; set; }
public string ParentProductName { get; set; }
public string SubscriptionIds { get; set; }
public int GroupId { get; set; }
public List<SubscriptionChildViewModel> ListOfSubscriptionChild { get; set; }
public List<AdminViewModel> ListOfAdmin { get; set; }
}
class SubscriptionChildViewModel
{
public string ChildProductName { get; set; }
public int ChildProductId { get; set; }
}
class AdminViewModel
{
public int id { get; set; }
public string name { get; set; }
}
class admin
{
public int id { get; set; }
public string name { get; set; }
}
void Main()
{
List<Subscription> ListOfSubscription = new List<Subscription>();
List<admin> ListOfAdmin = new List<admin>();
ListOfSubscription.Add(new Subscription() { SubscriptionId = 1, ParentProductId = 4, ChildProductId = 4, ParentProductName = "Product 1", ChildProductName = "Product 1", GroupId = 362,ListOfAdmin= ListOfAdmin });
ListOfAdmin.Clear();
ListOfAdmin.Add(new admin() { id = 1, name= "Mike"});
ListOfAdmin.Add(new admin() { id = 2, name = "Bill" });
ListOfSubscription.Add(new Subscription() { SubscriptionId = 2, ParentProductId = 114, ChildProductId = 1, ParentProductName = "Product 2", ChildProductName = "Product 3", GroupId = 1, ListOfAdmin= ListOfAdmin });
ListOfSubscription.Add(new Subscription() { SubscriptionId = 3, ParentProductId = 114, ChildProductId = 2, ParentProductName = "Product 2", ChildProductName = "Product 4", GroupId = 1, ListOfAdmin = ListOfAdmin });
var groupedSubscriptions = ListOfSubscription.GroupBy(u => u.GroupId);
var result = groupedSubscriptions.Select(grp1 => new
{
GroupId = grp1.Key,
Subscriptions = grp1.GroupBy(subscr => new
{
subscr.ParentProductId,
subscr.ParentProductName,
//subscr.ListOfAdmin
})
.Select(grp2 => new SubscriptionViewModel
{
GroupId = grp1.Key,
ParentProductId = grp2.Key.ParentProductId,
ParentProductName = grp2.Key.ParentProductName,
SubscriptionIds = string.Join(",", grp2.Select(y => y.SubscriptionId)),
ListOfSubscriptionChild = grp2
.Where(subsc => subsc.ChildProductId != grp2.Key.ParentProductId)
.Select(subsc => new SubscriptionChildViewModel
{
ChildProductId = subsc.ChildProductId,
ChildProductName = subsc.ChildProductName
})
.ToList(),
ListOfAdmin = (grp2.SelectMany(y => y.ListOfAdmin).Count()) == 0 ? null : grp2.SelectMany(y => y.ListOfAdmin)
.Select(a => new AdminViewModel
{
id = a.id,
name = a.name
})
//.GroupBy(f => f.id)
.ToList(),
})
});
var x = result.SelectMany((s => s.Subscriptions));
Console.Write(x);
}
Updated: using List<IGrouping<int, AdminViewModel>> I am getting dups.
Let's take a look at the exact error: Cannot implicitly convert type 'System.Collections.Generic.List<System.Linq.IGrouping<int,Program.AdminViewModel>>' to 'System.Collections.Generic.List<Program.AdminViewModel>'.
It is pretty clear: you are trying to assign a value (of type List<IGrouping<int,Program.AdminViewModel>>) that is not of the expected type (List<Program.AdminViewModel>).
You can remedy this by changing SubscriptionViewModel, so that ListOfAdmin will be List<IGrouping<int, AdminViewModel>>, as #itectori suggested.
However, I don't think that's what you're looking for. If I understand correctly, ListOfAdmin should contain, well, the admins. If that is the case, simply select the first item of every IGrouping, like this:
ListOfAdmin = (grp2.SelectMany(y => y.ListOfAdmin).Count()) == 0 ? null : grp2.SelectMany(y => y.ListOfAdmin)
.Select(a => new AdminViewModel
{
id = a.id,
name = a.name
})
.GroupBy(f => f.id)
.Select(g => g.First())
.ToList(),
According to the documentation, GrouBy() returns an object of type IEnumerable<IGrouping<TKey,TElement>>.
In your case,
(grp2.SelectMany(y => y.ListOfAdmin).Count()) == 0 ? null : grp2.SelectMany(y => y.ListOfAdmin)
.Select(a => new AdminViewModel
{
id = a.id,
name = a.name
})
.GroupBy(f => f.id)
.ToList()
return an object of type List<IGrouping<int, AdminViewModel>>
In order for your code to work, you just need to change the type of the SubscriptionViewModel.ListOfAdmin attribute.
class SubscriptionViewModel
{
[...]
public List<IGrouping<int, AdminViewModel>> ListOfAdmin { get; set; }
}

LINQ. Loading related elements

I have an entity Contracts, ListKindWorks and KindWorks.
public partial class Contracts
{
public Contracts()
{
ListKindWorks = new HashSet<ListKindWorks>();
}
public int Id { get; set; }
...
public virtual ICollection<ListKindWorks> ListKindWorks { get; set; }
}
public partial class ListKindWorks
{
public int IdContract { get; set; }
public int IdKindWork { get; set; }
public virtual Contracts IdContractNavigation { get; set; }
public virtual KindWorks IdKindWorkNavigation { get; set; }
}
public partial class KindWorks
{
public KindWorks()
{
ListKindWorks = new HashSet<ListKindWorks>();
}
public int Id { get; set; }
public string Title { get; set; }
public virtual ICollection<ListKindWorks> ListKindWorks { get; set; }
}
I want to load related elements. Something like this pseudocode:
source = model.Contracts
.Select(c => new MyType
{
IdContract = c.Id,
KindWork = new List<Item>
{ Id = KindWorks.Id, Value = KindWorks.Title }
// or
// KindWork = c.ListKindWorks
// .Where(x => x.IdContract == c.Id)
// .Select(y => new Item
// { Id = y.IdKindWork, Value = y.IdKindWorkNavigation.Title })
...
})
.ToList();
public class Item
{
public int Id { get; set; }
public string Value { get; set; }
}
Can I load List<Item> for each Contracts?
If I understand what you are looking for, I create a List for each contract in a dictionary. And here is my result:
var contracts = new List<Contracts>
{
new Contracts { Id = 1 },
new Contracts { Id = 2 },
new Contracts { Id = 3 },
};
var listKindWorks = new List<ListKindWorks>
{
new ListKindWorks { IdContract = 1, IdKindWork = 1 },
new ListKindWorks { IdContract = 1, IdKindWork = 2 },
new ListKindWorks { IdContract = 2, IdKindWork = 2 },
new ListKindWorks { IdContract = 2, IdKindWork = 3 }
};
var kindWorks = new List<KindWorks>
{
new KindWorks { Id = 1, Title = "Title 1" },
new KindWorks { Id = 2, Title = "Title 2" },
new KindWorks { Id = 3, Title = "Title 3" },
};
Dictionary<Contracts, List<Item>> myDic = contracts.Select(
contract => contract).ToDictionary(
contract => contract,
contract => listKindWorks.Where(
listKindWork => listKindWork.IdContract.Equals(contract.Id))
.Select(listKindWork => new Item
{
Id = kindWorks.FirstOrDefault(kindWork => kindWork.Id.Equals(listKindWork.IdKindWork))?.Id?? listKindWork.IdKindWork,
Value = kindWorks.FirstOrDefault(kindWork => kindWork.Id.Equals(listKindWork.IdKindWork))?.Title?? "KindWork not found"
}).ToList());
I obtain this for my test :
Contract1 : Title1, Title2
Contract2 : Title2, Title3
Contract3 : Nothing
IEnumerable<Item> KindWork = c.ListKindWorks
.Select(y => new Item
{
Id = y.IdKindWork,
Value = y.IdKindWorkNavigation.Title
})
IEnumerable<Item> Subject = c.ListSubjects
.Select(y => new Item
{
Id = y.IdSubject,
Value = y.IdSubjectNavigation.Title
})

c# Group linq results into a new list of a particular class

How do I need to write to iterate through the results of each of those three initial lists in order to return a single List. Title is the grouping value.
var invoiced = new List<Anonim>
{
new Anonim {Category = 1, Title = "Legal", Amount = 20},
new Anonim {Category = 2, Title = "Accounting", Amount = 10}
}
var settled = new List<Anonim> {
new Anonim {Category = 1, Title = "Legal", Amount = 10}
}
var credit = new List<Anonim> {
new Anonim {Category = 1, Title = "Legal", Amount = 30},
new Anonim {Category = 2, Title = "Accounting", Amount = 20}
}
var result = new List<Result> {
new Result {Title = credit.Title, Invoiced = invoiced.Amount, Settled = settled.Amount, SumAmount = credit.Amount + settled.Amount + invoiced.Amount },
new Result {Title = credit.Title, Invoiced = invoiced.Amount, Settled = settled.Amount, SumAmount = credit.Amount + settled.Amount + invoiced.Amount }
}
public class Result
{
public string Title { get; set; }
public decimal Credit { get; set; }
public decimal Invoiced { get; set; }
public decimal Settled { get; set; }
public decimal SumAmount { get; set; }
}
public class Anonim {
public int Category { get; set; }
public string Title { get; set; }
public decimal Amount { get; set; }
}
SumAmount is the sum of Invoiced, settled, credit of each item
It's a little unclear what you want to happen, but assuming you want to group by the Title property, here's one method. First you project each list into the Result class, making sure to set the relevant properties for each one, union them together into a big list and then group them to get the totals:
var groupedResults = invoiced.Select(i => new Result
{
Title = i.Title,
Invoiced = i.Amount
}).Union(settled.Select(i => new Result
{
Title = i.Title,
Settled = i.Amount
})).Union(credit.Select(i => new Result
{
Title = i.Title,
Credit = i.Amount
}));
var result = groupedResults
.GroupBy(r => r.Title)
.Select(g => new Result
{
Title = g.Key,
Invoiced = g.Sum(r => r.Invoiced),
Settled = g.Sum(r => r.Settled),
Credit = g.Sum(r => r.Credit),
SumAmount = g.Sum(r => r.Invoiced+r.Settled+r.Credit)
});
If I understood you correctly, this is something you want, however this is inefficient due to numerous collection traversals. Maybe #DavidG solution will be more performant.
var groupedSum = invoiced.Union(settled).Union(credit).GroupBy(g => g.Title).Select(g => new Result
{
Title = g.Key,
Credit = credit.Where(c => c.Title == g.Key).Sum(c => c.Amount),
Settled = settled.Where(c => c.Title == g.Key).Sum(c => c.Amount),
Invoiced = invoiced.Where(c => c.Title == g.Key).Sum(c => c.Amount),
SumAmount = g.Sum(i => i.Amount)
});
This is simplest I can find :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ConsoleApplication73
{
class Program
{
static void Main(string[] args)
{
List<Anonim> invoiced = new List<Anonim>
{
new Anonim {Category = 1, Title = "Legal", Amount = 20},
new Anonim {Category = 2, Title = "Accounting", Amount = 10}
};
List<Anonim> settled = new List<Anonim> {
new Anonim {Category = 1, Title = "Legal", Amount = 10}
};
List<Anonim> credit = new List<Anonim> {
new Anonim {Category = 1, Title = "Legal", Amount = 30},
new Anonim {Category = 2, Title = "Accounting", Amount = 20}
};
List<Result> results = new List<Result>();
List<string> titles = invoiced.Select(x => x.Title).ToList();
titles.AddRange(settled.Select(x => x.Title).ToList());
titles.AddRange(credit.Select(x => x.Title).ToList();
titles = titles.Distinct().ToList();
foreach(string title in titles)
{
Result newResult = new Result();
results.Add(new Result);
newResult.Title = title;
newResult.Credit = credit.Where(x => x.Title == title).Sum(x => x.Amount);
newResult.Invoiced = invoiced.Where(x => x.Title == title).Sum(x => x.Amount);
newResult.Settled = settled.Where(x => x.Title == title).Sum(x => x.Amount);
newResult.SumAmount = newResult.Credit + newResult.Invoiced + newResult.Settled;
}
}
}
public class Result
{
public string Title { get; set; }
public decimal Credit { get; set; }
public decimal Invoiced { get; set; }
public decimal Settled { get; set; }
public decimal SumAmount { get; set; }
}
public class Anonim
{
public int Category { get; set; }
public string Title { get; set; }
public decimal Amount { get; set; }
}
}
var invoiced = new List<Anonim>
{
new Anonim {Category = 1, Title = "Legal", Amount = 20},
new Anonim {Category = 2, Title = "Accounting", Amount = 10}
};
var settled = new List<Anonim> {
new Anonim {Category = 1, Title = "Legal", Amount = 10}
};
List<Anonim> credit = new List<Anonim> {
new Anonim {Category = 1, Title = "Legal", Amount = 30},
new Anonim {Category = 2, Title = "Accounting", Amount = 20}
};
List<Result> x = new List<Result>();
x.AddRange(invoiced.Select(y => new Result { Title = y.Title, Invoiced = y.Amount }));
x.AddRange(settled.Select(y => new Result { Title = y.Title, Invoiced = y.Amount }));
x.AddRange(credit.Select(y => new Result { Title = y.Title, Invoiced = y.Amount }));
var FinalList = x.GroupBy(a => a.Title).Select(Fn => new Result {
Title =Fn.Key,
Invoiced = Fn.Sum(a => a.Invoiced),``
Settled = Fn.Sum(a => a.Settled),
Credit = Fn.Sum(a => a.Credit),
SumAmount = Fn.Sum(a => a.Invoiced + a.Settled + a.Credit)
});

Cannot group data in LINQ

I have a question about a LINQ grouping.
I thought that grouping would be a simple matter of using the GroupBy function on the result set and specifying what to group it by. However my items appear to not be grouping together and instead are displaying as if the GroupBy function wasn't there. I want to group by the itemPk, but I'm can't seem to do it. I have tried grouping by both category.ItemFk and Item.Itempk, but no luck. Could someone give me a pointer on this?
var itemIds = items.Select(i => i.ItemId).ToList();
var itemAndCatJoin =
from item in Context.SCS_Items
join category in Context.SCS_ItemCategories
on item.ItemPk equals category.ItemFk
into temp
from category in temp.DefaultIfEmpty()
select new ExportItemTable
{
Category = category,
Item = item
};
return itemAndCatJoin.Where(i => itemIds.Contains(i.Item.ItemPk))
.GroupBy(n => new {n.Item, n.Category})
.Select(i => new ExportableItem
{
ItemPk = i.Key.Item.ItemPk,
Name = i.Key.Item.Name,
Description = i.Key.Item.Description,
Price = i.Key.Item.Price,
Category = i.Key.Category.Category.Category_Name,
GLDepartment = i.Key.Category.GL_Department.Name ?? "",
GLName = i.Key.Category.GL_Name.Name ?? "",
StartDate = i.Key.Item.StartDate,
EndDate = i.Key.Item.EndDate,
FiscalYear = i.Key.Item.SCS_FiscalYear.Name,
School = i.Key.Item.School != null ? i.Key.Item.School.School_Name : i.Key.Item.Board.Board_Name,
Beneficiary = i.Key.Item.SCS_Beneficiary.Name,
Quantity = i.Key.Item.MaxQuantity,
Deleted = i.Key.Item.DeletedFlag,
OptionalStudents = i.Key.Item.SCS_Attachments.Where(a => !a.IsRequired).SelectMany(a => a.SCS_StudentAttachments).Where(s => !s.DeletedFlag).Select(s => s.StudentFk).Distinct().Count(),
RequiredStudents = i.Key.Item.SCS_Attachments.Where(a => a.IsRequired).SelectMany(a => a.SCS_StudentAttachments).Where(s => !s.DeletedFlag).Select(s => s.StudentFk).Distinct().Count(),
IsPublic = i.Key.Item.IsPublic,
AllowRecurring = i.Key.Item.AllowRecurringPayments,
EffectiveCutoff = i.Key.Item.SCS_Attachments.Where(a => !a.DeletedFlag && a.CourseDropCutoff.HasValue).Select(a => a.CourseDropCutoff).OrderBy(a => a).FirstOrDefault(),
CreatedDate = i.Key.Item.CreatedDate
}).OrderBy(i => i.ItemPk).ToList();
}
your groupbyy is indeed doing nothing for you, you need to tell the groupby what to group by....
like
.GroupBy(n => n.Category)
Here is a simple example to your grouping question:
class Program
{
static void Main()
{
var allItems = GetAllItems();
var groups = from item in allItems
group item by item.Category
into newGroup
select newGroup;
foreach (var group in groups)
{
Console.WriteLine($"\nCategory: {group.Key}");
foreach (var item in group)
{
Console.WriteLine($"{item.Name}: {item.Price}");
}
}
Console.ReadLine();
}
static List<Category> GetAllCategories()
{
return new List<Category>()
{
new Category() { Id = 1, Name = "Programming Books" },
new Category() { Id = 2, Name = "Fiction Books" }
};
}
static List<Item> GetAllItems()
{
return new List<Item>()
{
new Item() { Id = 1, Name = "Embedded Linux", Category = 1, Price = 9.9 },
new Item() { Id = 2, Name = "LINQ In Action", Category = 1, Price = 36.19 },
new Item() { Id = 3, Name = "C# 6.0 and the .NET 4.6 Framework", Category = 1, Price = 40.99 },
new Item() { Id = 4, Name = "Thinking in LINQ", Category = 1, Price = 36.99 },
new Item() { Id = 5, Name = "The Book Thief", Category = 2, Price = 7.99 },
new Item() { Id = 6, Name = "All the Light We Cannot See", Category = 2, Price = 16.99 },
new Item() { Id = 7, Name = "The Life We Bury", Category = 2, Price = 8.96 }
};
}
}
public class Item
{
public int Id { get; set; }
public string Name { get; set; }
public double Price { get; set; }
public int Category { get; set; }
}
public class Category
{
public int Id { get; set; }
public string Name { get; set; }
}
This example is simple enough for anyone new to LINQ. I am sure you can make some adjustment to make it work for your specific issue. Hope this will help.

IGrouping trouble

I have the following list
class Programm
{
public static void Main(string[] args)
{
List<Service> Services =new List<Service>
{
new Service
{
Name = "name1",
Prices = new List<BEPrice>
{
new BEPrice
{
Price = 120,
Quantity = 3
}
}
},
new Service
{
Name = "name2",
Prices = new List<BEPrice>
{
new BEPrice
{
Price = 123,
Quantity = 3
}
}
},
new Service
{
Name = "name3",
Prices = new List<BEPrice>
{
new BEPrice
{
Price = 100,
Quantity = 3
}
}
},
new Service
{
Name = "name4",
Prices = new List<BEPrice>
{
new BEPrice
{
Price = 900,
Quantity = 8
}
}
}
};
}
public class Tariff
{
public string Name { get; set; }
public List<BEPrice> Prices { get; set; }
}
public class Service
{
public string Name { get; set; }
public List<BEPrice> Prices { get; set; }
public Tariff Tariff;
}
public class BEPrice
{
public decimal Price { get; set; }
public int Quantity { get; set; }
}
I want a result as
Tariff-1 -> Name - "blabla", Prices = {
Price1 = {Price = 343, Quantity = 3},
Price2 = {Price = 900, Quantity = 8} }
The tariff first price Price1 343 is a sum of 100, 120, 123 for 3 (Quantity) month.
Here is my unsuccessful attemp
foreach (var groupedPrices in Services.Select(s => s.Prices.GroupBy(p => p.Quantity)))
{
foreach (var p in groupedPrices.Select(x => x.Key))
Console.WriteLine(p);
foreach (var price in groupedPrices)
{
_prices.AddRange(price.Select(p => p));
}
}
Not sure what is name blabla, but this is how you can get prices part
var prices = Services
.SelectMany(arg => arg.Prices)
.GroupBy(arg => arg.Quantity)
.Select(arg => new { Price = arg.Sum(x => x.Price), Quantity = arg.Key })
.ToList();

Categories