How to make 2 dictionary and group it twice - c#

I am calculating totals per month for each country. I have managed to group data by country, but I get error
An item with the same key has already been added.
when trying to put monthly totals into inner dictionary:
var totalPerMonth = data.AsEnumerable()
.Select(x => new
{
Date = Convert.ToDateTime(x.ItemArray[0]).ToString("yyyy-MM"),
Country = x.ItemArray[1],
Revenue = x.ItemArray[2]
})
.GroupBy(x => x.Country)
.ToDictionary(x => x.Key, x => x.ToDictionary(p => p.Date,////this is not unique/// p => Convert.ToDouble(p.Revenue)));
how to group it to make Date key unique?

You can either use ToLookup instead of ToDictionary to allow several values for same date.
Or you can use grouping to get unique dates only (assume you want to calculate totals for each month, so use Sum of revenue for each date group dg ):
var totalPerMonth = data.AsEnumerable()
.Select(x => new {
Date = Convert.ToDateTime(x.ItemArray[0]).ToString("yyyy-MM"),
Country = x.ItemArray[1],
Revenue = Convert.ToDouble(x.ItemArray[2]) // convert here
})
.GroupBy(x => x.Country)
.ToDictionary(
g => g.Key,
g => g.GroupBy(x => x.Date).ToDictionary(dg => dg.Key, dg => dg.Sum(x => x.Revenue))
);

Related

Order by and group by and sum using SQL

What I am trying to do is get the top 10 most sold Vegetables by grouping them by an Id passed by parameter in a function and ordering them by the sum of their Quantity. I don't know how to use SUM or (total) quite yet but I thought I'd post it here seeking help. If you need me offering you anything else I will be ready.
This is my code:
TheVegLinQDataContext db = new TheVegLinQDataContext();
var query =db.OrderDetails.GroupBy(p => p.VegID)
.Select(g => g.OrderByDescending(p => p.Quantity)
.FirstOrDefault()).Take(10);
And this is an image of my database diagram
Group orders by Vegetable ID, then from each group select data you want and total quantity:
var query = db.OrderDetails
.GroupBy(od => od.VegID)
.Select(g => new {
VegID = g.Key,
Vegetable = g.First().Vegetable, // if you have navigation property
Total = g.Sum(od => od.Quantity)
})
.OrderByDescending(x => x.Total)
.Select(x => x.Vegetable) // remove if you want totals
.Take(10);
Since this is not clear that you are passing what type of id as function parameter, I'm assuming you are passing orderId as parameter.
First apply where conditions then group the result set after that order by Total sold Quantity then apply Take
LINQ query
var result = (from a in orderdetails
where a.OrderId == orderId //apply where condition as per your needs
group a by new { a.VegId } into group1
select new
{
group1.Key.VegId,
TotalQuantity = group1.Sum(x => x.Quantity),
group1.FirstOrDefault().Vegitable
}).OrderByDescending(a => a.TotalQuantity).Take(10);
Lamda (Method) Syntax
var result1 = orderdetails
//.Where(a => a.OrderId == 1) or just remove where if you don't need to filter
.GroupBy(x => x.VegId)
.Select(x => new
{
VegId = x.Key,
x.FirstOrDefault().Vegitable,
TotalQuantity = x.Sum(a => a.Quantity)
}).OrderByDescending(x => x.TotalQuantity).Take(10);

LINQ TO SQL Limited select statement because of group by

I am looking to find all the dealers in the database that have a duplicate phone number. I then want to list them in a report with all the dealers information. I am having trouble getting my select statement to populate the dealer record attributes.
Such as dealer name address and so fourth. I am thinking it is because of the group by that is limiting it.
var dealers = _db.Dealers
.Where(x => x.Active)
.GroupBy(x => x.Phone)
.Select(x => new { Dealer = x.Key, Phone = x.Count()})
.Where(x => x.Phone > 1);
Edit:
The desired output would be list of each dealer. I want the dealers with the same phone number to appear next to each other. I don't want any records that are not duplicates based on phone number.
Just add the first item in the group to the last Select:
var dealers = _db.Dealers
.Where(x => x.Active)
.GroupBy(x => x.Phone)
.Select(x => new { Dealer = x.Key, Phone = x.Count(), FirstItem = x.First()})
.Where(x => x.Phone > 1);
the result will then have a FirstItem property
Or if you want all the items in a flat list you can apply the Where directly to the grouping:
var dealers = _db.Dealers
.Where(x => x.Active)
.GroupBy(x => x.Phone)
.Where(g => g.Count() > 1);
.SelectMany(g => g) // flat list of Dealers
You're not saying exactly what the expected output and the actual output is, so I don't know what you mean by 'having trouble'. But I spotted one potentially confusing thing:
You're grouping by the Phone (.GroupBy(x => x.Phone)).
So when you do new { Dealer = x.Key, ... the x.Key will refer to the phone number of this group.

Find MAX/MIN list item using LINQ?

I have a list Having multiple Items and 3 props ID,DATE,COMMENT.ID field is Auto incremented in DATABASE.
Let say list Contains
2,16AUG,CommentMODIFIED
1,15AUG,CommentFIRST
3,18AUG,CommentLASTModified
I want to get a single ITEM.Item Having Minimum DATE and having Latest Comment. In this case
1,15AUG,CommentLASTModified
Any easy way to do it using LINQ.
orderedItems = items.OrderBy(x => x.Date);
var result = items.First();
result.Comment = items.Last().Comment;
To get a single item out of the list, you can order the items then take the first one, like this:
var result = items
.OrderByDescending(x => x.Date)
.First();
But First will throw an exception if the items collection is empty. This is a bit safer:
var result = items
.OrderByDescending(x => x.Date)
.FirstOrDefault();
To get the min / max of different columns you can do this:
var result =
new Item {
Id = 1,
Date = items.Min(x => x.Date),
Comment = items.Max(x => x.Comment)
};
But this will require two trips to the database. This might be a bit more efficient:
var result =
(from x in items
group x by 1 into g
select new Item {
Id = 1,
Date = g.Min(g => g.Date),
Comment = g.Max(g => g.Comment)
})
.First();
Or in fluent syntax:
var result = items
.GroupBy(x => 1)
.Select(g => new Item {
Id = 1,
Date = g.Min(g => g.Date),
Comment = g.Max(g => g.Comment)
})
.First();

Group List of Dictionaries by a Dictionary-key (C#)

I have a List of Dictionaries of type <String, String>. Dictionaries have the keys Revenue and Month.
A typical entry could be: Revenue = "10.080", Month = "1/2011"
I would like to get the revenue totals for each month, so I tried:
List<decimal> monthsTotals = data.Select(d => Convert.ToDecimal(d["Revenue"]))
.GroupBy(d => d["Month"]).ToList<decimal>();
This does not work. The expression d["Month"]) is underlined.
Cannot apply indexing with [] to an expression of type 'decimal'.
The result of your Select is just the revenue. You're losing all the rest of that information. I suspect you want:
Dictionary<string, decimal> revenueByMonth =
data.GroupBy(d => d["Month"], d => decimal.Parse(d["Revenue"]))
.ToDictionary(group => group.Key, group => group.Sum());
The first step creates an IGrouping<string, decimal> - i.e. for each month, a sequence of revenue values.
The second step converts this into a Dictionary<string, decimal> by taking the group key (the month) as the dictionary key, and the sum of the group values as the dictionary value.
List<decimal> monthsTotals = data
.GroupBy(d => d["Month"])
.Select(d => d.Sum( r => Convert.ToDecimal(r["Revenue"])))
.ToList<decimal>();
Turn those dictionaries into something useful.
public class RevenueData
{
public decimal Revenue {get;set;}
public string Month {get;set;}
}
List<RevenueData> result = data
.Select(d => new RevenueData()
{ Revenue = Convert.ToDecimal(d["Revenue"]), Month = d["Month"] })
.GroupBy(x => x.Month)
.Select(g => new RevenueData()
{ Revenue = g.Sum(x => x.Revenue), Month = g.Key })
.ToList();

How to use Linq group a order list by Date

I have a order list and want to group them by the created date.
Each order's created datetime will be like "2010-03-13 11:17:16.000"
How can I make them only group by date like "2010-03-13"?
var items = orderList.GroupBy(t => t.DateCreated)
.Select(g => new Order()
{
DateCreated = g.Key
})
.OrderByDescending(x => x.OrderID).ToList();
Update: How can I group order by month? And the following code is not correct.
var items = orderList.GroupBy(t => t.DateCreated.Month)
.Select(g => new Order()
{
DateCreated = g.Key
})
.OrderByDescending(x => x.OrderID).ToList();
Many thanks.
Use the Date property.
var items = orderList.GroupBy( t => t.DateCreated.Date )
Using the .Date will discard the time component, e.g.
var items = orderList.GroupBy(t => t.DateCreated.Date)
Use t => t.DateCreate.Date.

Categories