i want to run and print a query that shows the number of orders per each hour in a day(24).
should look like:
hour-1:00, number of orders-5
hour-2:00, number of orders-45
hour-3:00, number of orders-25
hour-4:00, number of orders-3
hour-5:00, number of orders-43
and so on...
i try:
public void ShowBestHours()
{
using (NorthwindDataContext db = new NorthwindDataContext())
{
var query =
from z in db.Orders
select new Stime
{
HourTime = db.Orders.GroupBy(x => x.OrderDate.Value.Hour).Count(),
};
foreach (var item in query)
{
Console.WriteLine("Hour : {0},Order(s) Number : {1}", item.HourTime, item.Count);
}
}
}
public class Stime
{
public int HourTime { get; set; }
public int Count { get; set; }
}
You need to change your query to
var query =
from z in db.Orders
group z by z.OrderDate.Value.Hour into g
select new Stime{ HourTime = g.Key, Count=g.Count () };
or alternatively
var query = db,Orders.GroupBy (o => o.OrderDate.Value.Hour).Select (
g => new Stime{ HourTime=g.Key, Count=g.Count () });
In my copy of Northwind all of the OrderDate values are dates only so the result is just
HourTime = 0, Count = 830.
I'm assuming you're just experimenting with grouping. Try grouping by day of week like this
var query = db.Orders.GroupBy (o => o.OrderDate.Value.DayOfWeek).Select (
g => new { DayOfWeek=g.Key, Count=g.Count () });
which gives a more useful result.
You aren't setting Stime.Count anywhere in your query and you aren't grouping by hour correctly. I haven't seen your exact setup of course, but I think the following should work for you.
var query =
from z in db.Orders
group z by z.OrderDate.Value.Hour into g
select new Stime() { HourTime = g.Key, Count = g.Count() };
foreach (var item in query)
{
Console.WriteLine("Hour : {0},Order(s) Number : {1}", item.HourTime, item.Count);
}
Try this:
public void ShowBestHours()
{
using (NorthwindDataContext db = new NorthwindDataContext())
{
var query = db.Orders.GroupBy(x => x.OrderDate.Value.Hour).OrderByDescending(x => x.Count()).Select(x => new Stime { HourTime = x.Key, Count = x.Count() });
foreach (var item in query)
{
Console.WriteLine("Hour : {0},Order(s) Number : {1}", item.HourTime, item.Count);
}
}
}
Related
I have a complex LINQ Query to extract Top students in my university. Here is the query :
var query = Db.Students.AsNoTracking().Where(...).AsQueryable();
var resultgroup = query.GroupBy(st => new
{
st.Student.CourseStudyId,
st.Student.EntranceTermId,
st.Student.StudyingModeId,
st.Student.StudyLevelId
}, (key, g) => new
{
CourseStudyId = key.CourseStudyId,
EntranceTermId = key.EntranceTermId,
StudyingModeId = key.StudyingModeId,
StudyLevelId = key.StudyLevelId,
list = g.OrderByDescending(x =>
x.StudentTermSummary.TotalAverageTillTerm).Take(topStudentNumber)
}).SelectMany(q => q.list).AsQueryable();
This Query give me top n students based on 4 parameters and on their TotalAverageTillTerm.
Now I want to add rownum for each group to simulate Total rank, for example Output is :
Now I want to Add TotalRank as rownumber like Sql. In the picture X1=1,X2=2,X3=3 and Y1=1,Y2=2,Y3=3
If I want to reduce problem. I only work on one group. Code Like this :
resultgroup = query.GroupBy(st => new
{
st.Student.StudyLevelId
}, st => st, (key, g) => new
{
StudyLevelId = key.StudyLevelId,
list = g.OrderByDescending(x =>
x.StudentTermSummary.TotalAverageTillTerm)
.Take(topStudentNumber)
}).SelectMany(q => q.list).AsQueryable();
list was a List of student but I see no sign of student having a rank property so I wrapped it into a annonimous type with rank.
var query = Db.Students.AsNoTracking().Where(...).AsEnumerable();
var resultgroup = query.GroupBy(st => new {
st.Student.CourseStudyId,
st.Student.EntranceTermId,
st.Student.StudyingModeId,
st.Student.StudyLevelId
})
.SelectMany( g =>
g.OrderByDescending(x =>x.StudentTermSummary.TotalAverageTillTerm)
.Take(topStudentNumber)
.Select((x,i) => new {
CourseStudyId = g.Key.CourseStudyId,
EntranceTermId = g.Key.EntranceTermId,
StudyingModeId = g.Key.StudyingModeId,
StudyLevelId = g.Key.StudyLevelId,
Rank = i+1
//studentPorperty = x.Prop1,
})
)
.AsQueryable();
Do you mean :
var query = Db.Students.AsNoTracking().Where(...).AsQueryable();
var resultgroup = query.GroupBy(st => new
{
st.Student.CourseStudyId,
st.Student.EntranceTermId,
st.Student.StudyingModeId,
st.Student.StudyLevelId
}, (key, g) => new
{
CourseStudyId = key.CourseStudyId,
EntranceTermId = key.EntranceTermId,
StudyingModeId = key.StudyingModeId,
StudyLevelId = key.StudyLevelId,
list = g.OrderByDescending(x =>
x.StudentTermSummary.TotalAverageTillTerm)
.Take(topStudentNumber)
.Select((x, i) => new { Item = x, TotalRank = i /* item number inside group */}),
StudentsInGroupCount = g.Count() // count group this items
}).SelectMany(q => q).AsQueryable();
To see the results :
foreach (var item in resultgroup.ToList())
{
item.list.ForEach(s => Console.WriteLine(s.TotalRank));
}
I am using a group by select using entity framework core and linq.
var list = context.Ways.GroupBY(s=>s.Type).Select(w=> new {
type = w.key,
total = (int)w.Sum(b => b.Length)
})
This giwes me a list.
type total
T1 2541
T2 5481
T5 4
T9 2
T11 856
T3 25
So I want to group into "Others", if total is smaller than 100 like following,
type total
T1 2541
T2 5481
T11 856
OTHERS 31
is this possible?
You can do this with a second group by
var list = context.Ways.GroupBy(s => s.Type).Select(w => new
{
type = w.Key,
total = (int)w.Sum(b => b.Length)
}).GroupBy(s => s.total < 100 ? "Others" : s.type)
.Select(w => new
{
type = w.Key,
total = (int)w.Sum(b => b.total)
});
You can't do this with Entity Framework, but you can write a method to iterate over the list in memory. For example, assuming you have a class to hold the key and value like this (or you could rewrite using KeyValuePair or a tuple):
public class ItemCount
{
public string Name { get; set; }
public int Count { get; set; }
}
An extension method to aggregate the smaller values could look like this:
public static IEnumerable<ItemCount> AggregateWithThreshold(this IEnumerable<ItemCount> source,
int threshold)
{
// The total item to return
var total = new ItemCount
{
Name = "Others",
Count = 0
};
foreach (var item in source)
{
if (item.Count >= threshold)
{
// If count is above threshold, just return the value
yield return item;
}
else
{
// Keep the total count
total.Count += item.Count;
}
}
// No need to return a zero count if all values were above the threshold
if(total.Count > 0)
{
yield return total;
}
}
And you would call it like this:
var list = context.Ways
.GroupBY(s => s.Type)
.Select(w => new ItemCount // Note we are using the new class here
{
Name = w.key,
Count = (int)w.Sum(b => b.Length)
});
var result = list.AggregateWithThreshold(100);
Technically you can add additional operation that would calculate the Others value based on 2 collection values you have already. Like this:
var list = context.Ways.GroupBy(s=>s.Type).Select(w=> new {
type = w.key,
total = (int)w.Sum(b => b.Length)
});
var totalSum = context.Ways.Sum(x => x.Length);
var listSum = list.Sum(x => x.total);
list.Add(new {
type = "Others",
total = totalSum - listSum
});
IEnumerable<IGrouping<long, MyClass>> datas = list.GroupBy(x => x.PropertyXYOfMyClass);
// get all items from each group
foreach (var grouping in datas)
{
long groupKey = groupingByMyClass.Key;
//iterating through values
foreach (var item in groupingByMyClass)
{
long key = item.PropertyIntOfClassA;
string property = item.PropertyA;
}
}
Each group contains some items, wow to get values from first item of each group?
UPDATE
void Extract()
{
List<DataHolder> data = new List<DataHolder>();
List<DateTime> randomTimes = new List<DateTime>();
Random r = new Random();
DateTime d = new DateTime(2019, 9, 19, 7, 0, 0);
for (int i = 0; i < 100; i++)
{
DataHolder dh = new DataHolder();
TimeSpan t = TimeSpan.FromSeconds(r.Next(0, 14400));
dh.OID = i;
dh.Value = r.Next(50);
dh.Snapshottime = d.Add(t);
data.Add(dh);
}
data.OrderBy(o => o.Snapshottime).ToList();
List<DataHolder> SortedList = data.OrderBy(o => o.Snapshottime).ToList();
TimeSpan interval = new TimeSpan(0, 15, 0);
var result = SortedList.GroupBy(x => x.Snapshottime.Ticks / interval.Ticks) .OrderBy(x => x.Key);
}
public class DataHolder
{
public int OID { get; set; }
public double Value { get; set; }
public DateTime Snapshottime { get; set; }
}
Here from result i need to take first item from each group.
try this:
var finalResult = result.Select(gpr=>grp.First());
or if you want the earliest/Latest/etc you could order by first:
var finalResult = result.Select(gpr=>grp.OrderBy(x=>x.SnapShotTime).First());
You've already done the heavy lifting. Make a simple loop over the result:
var result = SortedList.GroupBy(x => x.Snapshottime.Ticks / interval.Ticks) .OrderBy(x => x.Key);
var resultList = new List<DataHolder>();
foreach(var group in result)
{
resultList.Add(group.First());
}
I hope this helps.
List<MailingList> myGroup = lst.GroupBy(t => new {t.userId, t.userName,t.email,t.reportTypeId})
.Select(g => new MailingList
{
userId = g.Key.userId,
Acrynom = g.SelectMany(t => t.Acrynom).ToArray(),
userName = g.Key.userName,
email = g.Key.email,
reportTypeId = g.Key.reportTypeId
}).ToList();
foreach (var mailingList in myGroup.Distinct())
{
StringBuilder AcrynomsList1 = new StringBuilder();
foreach (var item in mailingList.Acrynom)
{
if (Acrynoms.Length > 0)
{
Acrynoms.Append(", ");
}
AcrynomsList1.Append(item);
}
}
What i want to achieve is filter and group myGroup by reportTypeId. reportTypeId can either be 1 or 2, so i want to have a variable StringBuilder AcrynomsList1 where reportTypeId = 1 and then another variable StringBuilder AcrynomsList2 where reportTypeId = 2.
My current StringBuilder varibale AcrynomsList1 has all reportTypeId 1 & 2 values.
This should give you what you want:
var list = lst.GroupBy(x => x.reportTypeId)
.Select(x => new
{
reportTypeId = x.Key,
Acronyms = x.SelectMany(t => t.Acrynom).ToArray()
}).ToList();
var acronymList1 = string.Join(", ", list[0].Acronyms);
var acronymList2 = string.Join(", ", list[1].Acronyms);
You can group it straight into a string without using a StringBuilder:
class Program
{
static void Main(string[] args)
{
var list = new List<MailingList>();
var grouped = list
.GroupBy(m => m.ReportTypeID)
.Select(g => new
{
ReportTypeID = g.Key,
Items = string.Join(", ", g.Where(s => !string.IsNullOrEmpty(s.Acronym)).Select(m => m.Acronym))
});
}
}
class MailingList
{
public int ReportTypeID { get; set; }
public string Acronym { get; set; }
}
The GroupBy extension method returns a number of enumerables of MailingList for you, which has a Key to expose the key you grouped by. The Distinct is part of the GroupBy, so you don't need it.
I am unable to solve this problem with the LINQ Query.
So we have the table structure as follows:
Id || bug_category || bug_name || bug_details || bug_priority
I want to group by bug_category first. For each bug_category, I want to in turn group by bug__priority.
So basically I want something like :
bug_category = AUDIO :: No of BUGS --> Critical = 3, Medium = 2 and Low = 7 bugs.
bug_category = VIDEO :: No of BUGS --> Critical = 5, Medium = 1 and Low = 9 bugs.
The below query returns all unique combinations of category AND customer_priority:
(where RawDataList is simply a List of data which has the above mentioned structure )
var ProceesedData = from d in RawDataList
group d by new { d.bug_category, d.bug_priority } into g
select new
{
g.Key.bug_category,
g.Key.bug_priority
};
The below query returns the category followed by a list of records in that category:
var ProceesedData = from d in RawDataList
group d by d.bug_category into g
select new { g.Key, records = g
};
But I am unable to proceed further as ProcessedData(the return variable) is an unknown type. Any thoughts on this?
This is an easier way to accomplish nested groupings. I've tested it for in memory collections, whether or not your particular DB provider will handle it well might vary, or whether it performs well is unknown.
Assuming you had two properties, and wanted to group by both State and Country:
var grouped = People
.GroupBy(l => new { l.State, l.Country})//group by two things
.GroupBy(l=> l.Key.Country)//this will become the outer grouping
foreach(var country in grouped)
{
foreach(var state in country)
{
foreach(var personInState in state)
{
string description = $"Name: {personInState.Name}, State: {state.StateCode}, Country: {country.CountryCode}";
...
}
}
}
I suspect you want (names changed to be more idiomatic):
var query = from bug in RawListData
group bug by new { bug.Category, bug.Priority } into grouped
select new {
Category = grouped.Key.Category,
Priority = grouped.Key.Priority,
Count = grouped.Count()
};
Then:
foreach (var result in query)
{
Console.WriteLine("{0} - {1} - {2}",
result.Category, result.Priority, result.Count);
}
Alternatively (but see later):
var query = from bug in RawListData
group bug by new bug.Category into grouped
select new {
Category = grouped.Category,
Counts = from bug in grouped
group bug by grouped.Priority into g2
select new { Priority = g2.Key, Count = g2.Count() }
};
foreach (var result in query)
{
Console.WriteLine("{0}: ", result.Category);
foreach (var subresult in result.Counts)
{
Console.WriteLine(" {0}: {1}", subresult.Priority, subresult.Count);
}
}
EDIT: As noted in comments, this will result in multiple SQL queries. To obtain a similar result structure but more efficiently you could use:
var dbQuery = from bug in RawListData
group bug by new { bug.Category, bug.Priority } into grouped
select new {
Category = grouped.Key.Category,
Priority = grouped.Key.Priority,
Count = grouped.Count()
};
var query = dbQuery.ToLookup(result => result.Category,
result => new { result.Priority, result.Count };
foreach (var result in query)
{
Console.WriteLine("{0}: ", result.Key);
foreach (var subresult in result)
{
Console.WriteLine(" {0}: {1}", subresult.Priority, subresult.Count);
}
}
I think you're searching something like that:
var processedData =
rawData.GroupBy(bugs => bugs.bug_category,
(category, elements) =>
new
{
Category = category,
Bugs = elements.GroupBy(bugs => bugs.bug_priority,
(priority, realbugs) =>
new
{
Priority = priority,
Count = realbugs.Count()
})
});
foreach (var data in processedData)
{
Console.WriteLine(data.Category);
foreach (var element in data.Bugs)
Console.WriteLine(" " + element.Priority + " = " + element.Count);
}
You can do it like this
var retList = (from dbc in db.Companies
where dbc.IsVerified && dbc.SellsPCBs && !dbc.IsDeleted && !dbc.IsSpam && dbc.IsApproved
select new
{
name = dbc.CompanyName,
compID = dbc.CompanyID,
state = dbc.State,
city = dbc.City,
businessType = dbc.BusinessType
}).GroupBy(k => k.state).ToList();
List<dynamic> finalList = new List<dynamic>();
foreach (var item in retList)
{
finalList.Add(item.GroupBy(i => i.city));
}